/*
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 * 
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <Xm/ColumnP.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/VaSimpleP.h>
#include "XmI.h"

#define XK_LATIN1
#include <X11/keysymdef.h>

static void ClassInitialize(void);

static void Initialize(Widget, Widget, ArgList, Cardinal*);
static void ClassPartInitialize(WidgetClass w_class);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal*);
static void Destroy(Widget);
static void Resize(Widget);
static XtGeometryResult QueryGeometry(Widget, 
        XtWidgetGeometry*, XtWidgetGeometry*);
static XtGeometryResult GeometryManager(Widget, 
        XtWidgetGeometry*, XtWidgetGeometry*);
static void ChangeManaged(Widget);
static void ConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
static Boolean ConstraintSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
static void ConstraintDestroy(Widget);
static void ConstraintGetValues(Widget, ArgList, Cardinal*);


static Boolean CvtStringToXiAlignment(
	Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer
);
static Boolean CvtStringToFillStyle(
	Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer
);
static Boolean CvtStringToDistribution(
	Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer
);

static void Layout(
	XmColumnWidget, Widget, XtWidgetGeometry*, int, int
);
static void HorizontalLayout(
	XmColumnWidget, Widget, XtWidgetGeometry*, int, int
);
static void VerticalLayout(
	XmColumnWidget, Widget, XtWidgetGeometry*, int, int
);
static void VerifyResources(
	XmColumnWidget, XmColumnWidget, XmColumnWidget
);
static void VerifyConstraints(
	Widget, Widget, Widget
);
static void CalcSize(
	XmColumnWidget, Widget, XtWidgetGeometry*, Boolean, Dimension*, Dimension*
);
static Boolean CompareGeometry(

	XtWidgetGeometry*, XtWidgetGeometry*

);
static Boolean CompareGeometryToWidget(
	XtWidgetGeometry*, Widget

);
static void CheckSetEntryLabelRenderTable(Widget wid, int offs, XrmValue *value); 
static void CheckSetDefaultEntryLabelRenderTable(Widget wid, int offs, XrmValue *value); 
static void XmColumnLabelDestroyedCallback(
	Widget, XtPointer, XtPointer
);

#if 0	/* POSITION HANDLING */
	Note: this code was never finished and has been pulled out. The
	public and semi-public traces have been pulled out of the header files.
	Everything is marked with the #if used above.
#endif

#define BBPart(w) ((XmBulletinBoardPart*)(&(((XmBulletinBoardWidget)(w))->bulletin_board)))
#define XiC(w) ((XmColumnConstraintPart*)(&((XmColumnConstraintPtr)((w)->core.constraints))->column))
#define XiValidChild(c) (((c)) != NULL && XtIsManaged((c)) && \
			 !(c)->core.being_destroyed && \
			 XiC(c)->label_widget != NULL)
#define XmColumn(c) ((XmColumnWidget) XtParent((c)))
#define XiAlignment(c) ((XiC((c))->label_alignment == XmALIGNMENT_UNSPECIFIED) \
			? XmColumn_default_label_alignment(XmColumn((c))) \
			: XiC(c)->label_alignment)
#if 0	/* POSITION HANDLING */
#define XiPosition(c) ((XiC(c)->label_position == XiLABEL_POSITION_UNSPECIFIED)\
		       ? XmColumn_default_label_position(XmColumn(c)) \
		       : XiC(c)->label_position)
#endif
#define XiFill(c) ((XiC(c)->fill_style == XmFILL_UNSPECIFIED)\
		   ? XmColumn_default_fill_style(XmColumn(c)) \
		   : XiC(c)->fill_style)

#define XiWidth(c) (XtWidth(c) + 2 * XtBorderWidth(c))
#define XiHeight(c) (XtHeight(c) + 2 * XtBorderWidth(c))


#if 0	/* POSITION HANDLING */

/* from public .h file */
#define XiLABEL_POSITION_UNSPECIFIED	0
#define XiLABEL_POSITION_CENTER 	(1L<<0)
#define XiLABEL_POSITION_LEFT		(1L<<1)
#define XiLABEL_POSITION_RIGHT		(1L<<2)
#define XiLABEL_POSITION_TOP		(1L<<3)
#define XiLABEL_POSITION_BOTTOM		(1L<<4)

/* structure member elements from private P.h file */
    unsigned char default_label_position;
    unsigned char       label_position;
#define XmColumnC_label_position(w) XmColCField(w, label_position, unsigned char)
#define XmColumn_default_label_position(w) XmColField(w, default_label_position, unsigned char)

#endif

#define DEFAULT_ALIGNMENT XmALIGNMENT_BEGINNING
#if 0	/* POSITION HANDLING */
#define DEFAULT_POSITION XiLABEL_POSITION_LEFT
#endif
#define DEFAULT_ORIENTATION XmVERTICAL
#define DEFAULT_FILL_STYLE XmFILL_RAGGED

static XtResource resources[] =
{
  {
    "pri.vate", "Pri.vate", XmRBoolean,
    sizeof(Boolean), XtOffsetOf(XmColumnRec, column.check_set_render_table),
    XmRImmediate, (XtPointer) False
  },

  {
    XmNdefaultEntryLabelFontList, XmCFontList, XmRFontList,
    sizeof(XmFontList), XtOffsetOf(XmBulletinBoardRec, bulletin_board.label_font_list),
    XmRCallProc, (XtPointer) CheckSetDefaultEntryLabelRenderTable
  },

  {
    XmNdefaultEntryLabelRenderTable, XmCRenderTable, XmRRenderTable,
    sizeof(XmRenderTable), XtOffsetOf(XmBulletinBoardRec, bulletin_board.label_font_list),
    XmRCallProc, (XtPointer) CheckSetDefaultEntryLabelRenderTable
  },

  {
    XmNdefaultEntryLabelAlignment, XmCAlignment, XmRXmAlignment,
    sizeof(unsigned char), XtOffsetOf(XmColumnRec, column.default_label_alignment),
    XmRImmediate, (XtPointer) DEFAULT_ALIGNMENT
  },
#if 0	/* POSITION HANDLING */
  {
    XmNdefaultEntryLabelPosition, XmCEntryLabelPosition, XmRLabelPosition,
    sizeof(unsigned char), XtOffsetOf(XmColumnRec, column.default_label_position),
    XmRImmediate, (XtPointer) DEFAULT_POSITION
  },
#endif
  {
    XmNdefaultFillStyle, XmCFillStyle, XmRFillStyle,
    sizeof(unsigned char), XtOffsetOf(XmColumnRec, column.default_fill_style),
    XmRImmediate, (XtPointer) DEFAULT_FILL_STYLE
  },

  {
    XmNitemSpacing, XmCItemSpacing, XmRVerticalDimension,
    sizeof(Dimension), XtOffsetOf(XmColumnRec, column.item_spacing),
    XmRImmediate, (XtPointer) 2
  },

  {
    XmNlabelSpacing, XmCLabelSpacing, XmRHorizontalDimension,
    sizeof(Dimension), XtOffsetOf(XmColumnRec, column.label_spacing),
    XmRImmediate, (XtPointer) 10
  },

  {
    XmNorientation, XmCOrientation, XmROrientation,
    sizeof(unsigned char), XtOffsetOf(XmColumnRec, column.orientation),
    XmRImmediate, (XtPointer) DEFAULT_ORIENTATION
  },

  {
    XmNdistribution, XmCDistribution, XmRDistribution,
    sizeof(unsigned char), XtOffsetOf(XmColumnRec, column.distribution),
    XmRImmediate, (XtPointer) XmDISTRIBUTE_TIGHT
  }
};

static XmSyntheticResource get_resources[] =
{
  {
    XmNlabelSpacing, sizeof(Dimension),
    XtOffsetOf(XmColumnRec, column.label_spacing),
    XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
  },

  {
    XmNitemSpacing, sizeof(Dimension),
    XtOffsetOf(XmColumnRec, column.item_spacing),
    XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
  }
};

static XtResource constraint_resources[] =
{
  {
    "pri.vate", "Pri.vate", XmRBoolean,
    sizeof(Boolean), XtOffsetOf(XmColumnConstraintRec, column.check_set_render_table),
    XmRImmediate, (XtPointer) False
  },

  {
    XmNentryLabelFontList, XmCFontList, XmRFontList,
    sizeof(XmFontList), XtOffsetOf(XmColumnConstraintRec, column.label_font_list),
    XmRCallProc, (XtPointer) CheckSetEntryLabelRenderTable
  },

  {
    XmNentryLabelRenderTable, XmCRenderTable, XmRRenderTable,
    sizeof(XmRenderTable), XtOffsetOf(XmColumnConstraintRec, column.label_font_list),
    XmRCallProc, (XtPointer) CheckSetEntryLabelRenderTable
  },

  {
    XmNentryLabelAlignment, XmCAlignment, XmRXmAlignment,
    sizeof(unsigned char), XtOffsetOf(XmColumnConstraintRec, column.label_alignment),
    XmRImmediate, (XtPointer) XmALIGNMENT_UNSPECIFIED
  },
#if 0	/* POSITION HANDLING */
  {
    XmNentryLabelPosition, XmCEntryLabelPosition, XmRLabelPosition,
    sizeof(unsigned char), XtOffsetOf(XmColumnConstraintRec, column.label_position),
    XmRImmediate, (XtPointer) XiLABEL_POSITION_UNSPECIFIED
  },
#endif
  {
    XmNfillStyle, XmCFillStyle, XmRFillStyle,
    sizeof(unsigned char), XtOffsetOf(XmColumnConstraintRec, column.fill_style),
    XmRImmediate, (XtPointer) XmFILL_UNSPECIFIED
  },

  { 
    XmNentryLabelType, XmCLabelType, XmRLabelType,
    sizeof(unsigned char), XtOffsetOf(XmColumnConstraintRec, column.label_type),
    XmRImmediate, (XtPointer) XmSTRING
  },

  {
      XmNentryLabelString, XmCLabelString, XmRXmString,
      sizeof(XmString), XtOffsetOf(XmColumnConstraintRec, column.label_string),
      XmRImmediate, (XtPointer) NULL
  },

  {
      XmNentryLabelPixmap, XmCLabelPixmap, XmRPrimForegroundPixmap,
      sizeof(Pixmap), XtOffsetOf(XmColumnConstraintRec, column.label_pixmap),
      XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
  },

  {
      XmNshowEntryLabel, XmCShowLabel, XmRBoolean,
      sizeof(Boolean), XtOffsetOf(XmColumnConstraintRec, column.show_label),
      XmRImmediate, (XtPointer) True
  },
  
  {
      XmNstretchable, XmCStretchable, XmRBoolean,
      sizeof(Boolean), XtOffsetOf(XmColumnConstraintRec, column.stretchable),
      XmRImmediate, (XtPointer) False
  }
};

/*
 * Synthetic constraints.  Note that these are NOT currently used,
 * as the constraint get_values_hook method below seems to work where
 * synthetic resources don't.  Dunno.
 */
static void Get_entryLabelString(Widget, int, XtArgVal *);
static XmSyntheticResource cont_get_resources[] =
{
  {
    XmNentryLabelString, sizeof(XmString),
    XtOffsetOf(XmColumnConstraintRec, column.label_string),
    Get_entryLabelString, (XmImportProc) NULL
  }
};

ConstraintClassExtensionRec xiColumnConstraintExtension = {
    NULL,			         /* next_extension  */
    NULLQUARK,			         /* record_type     */
    XtConstraintExtensionVersion,        /* version         */
    sizeof(ConstraintClassExtensionRec), /* record_size     */
    ConstraintGetValues		         /* get_values_hook */
};

XmColumnClassRec xmColumnClassRec = {
  {
    /* core_class members      */
    /* superclass         */	(WidgetClass) &xmBulletinBoardClassRec,
    /* class_name         */	"XmColumn",                            
    /* widget_size        */	sizeof(XmColumnRec),
    /* class_initialize   */	ClassInitialize,
    /* class_part_init    */	ClassPartInitialize,
    /* class_inited       */	False,                            	
    /* initialize         */	Initialize, 
    /* initialize_hook    */	NULL,                             	
    /* realize            */	XtInheritRealize,
    /* actions            */	NULL,
    /* num_actions        */	0,
    /* 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             */	XtInheritExpose,
    /* set_values         */	SetValues,                             
    /* set_values_hook    */	NULL,                             
    /* set_values_almost  */	XtInheritSetValuesAlmost,         
    /* get_values_hook    */	NULL,                             	
    /* accept_focus       */	NULL,                             
    /* version            */	XtVersion,
    /* callback_private   */	NULL,                             
    /* tm_table           */	XtInheritTranslations,
    /* query_geometry     */	(XtGeometryHandler) QueryGeometry, 
    /* display_accelerator*/	NULL,                             
    /* extension          */	NULL,                             
  },
  {
    /* composite_class members */
    /* geometry_manager   */	GeometryManager,
    /* change_managed     */	ChangeManaged,                    
    /* insert_child       */	XtInheritInsertChild,
    /* delete_child       */	XtInheritDeleteChild,
    /* extension          */	NULL,                             
  },
  { /* constraint_class fields */
    /* resource list      */    (XtResource*)constraint_resources,
    /* num resources      */ 	XtNumber(constraint_resources),
    /* constraint size    */ 	sizeof(XmColumnConstraintRec),
    /* init proc          */ 	ConstraintInitialize,
    /* destroy proc       */ 	ConstraintDestroy,
    /* set values proc    */ 	ConstraintSetValues,
    /* extension          */ 	&xiColumnConstraintExtension,
  },
  { /* manager_class fields */
    /* default translations */ 	XtInheritTranslations,
    /* syn_resources        */ 	get_resources,
    /* num_syn_resources    */ 	XtNumber(get_resources),
    /* syn_cont_resources   */ 	NULL, /* cont_get_resources, */
    /* num_syn_cont_resources */ 0, /* XtNumber(cont_get_resources),*/
    /* parent_process       */ 	XmInheritParentProcess,
    /* extension            */ 	NULL,
  },
  { /* bulletin board members */
    /* always_install_accel */  False,
    /* geo_matrix_create    */  NULL,
    /* focus_moved_proc     */  XmInheritFocusMovedProc,
    /* extension            */  NULL,
  },
  {
    /* column class members */
    /* extension            */	NULL,                                
  }
};

WidgetClass xmColumnWidgetClass = (WidgetClass) &xmColumnClassRec;

/*
 * Function:
 *	ClassInitialize(void)
 * Description:
 *	This function is called the first time XmColumn or subclass is
 *	created.  This function is used to install all need type
 *	converters for this widget class.
 * Input:
 *	None.
 * Output:
 *	None.
 */
static void
ClassInitialize(void)
{
    XmColumnClassRec* wc = &xmColumnClassRec;

#if 0	/* POSITION HANDLING */
    XtSetTypeConverter(XmRString, XmRLabelPosition,
		       (XtTypeConverter) CvtStringToLabelPosition,
		       NULL, 0, XtCacheAll, NULL);
#endif
    XtSetTypeConverter(XmRString, XmRXmAlignment,
		       (XtTypeConverter) CvtStringToXiAlignment,
		       NULL, 0, XtCacheAll, NULL);
    XtSetTypeConverter(XmRString, XmRFillStyle,
		       (XtTypeConverter) CvtStringToFillStyle,
		       NULL, 0, XtCacheAll, NULL);
    XtSetTypeConverter(XmRString, XmRDistribution,
		       (XtTypeConverter) CvtStringToDistribution,
		       NULL, 0, XtCacheAll, NULL);
}

/*
 * ClassPartInitialize sets up the fast subclassing for the widget.
 */
static void 
#ifdef _NO_PROTO
ClassPartInitialize(w_class)
        WidgetClass w_class ;
#else
ClassPartInitialize(WidgetClass w_class)
#endif /* _NO_PROTO */
{
    _XmFastSubclassInit (w_class, XmCOLUMN_BIT);
}



/*
 * Function:
 *	Initialize(request, set, arg_list, arg_cnt)
 * Description:
 *	This function is called to initialize the resource values for each
 *	new widget instance.  This function verifies the resource values
 *	and takes the needed actions to initialize the new instance.
 * Input:
 *	request  : Widget   - user resource requests
 *	set      : Widget   - the resource values for the new widget
 *	arg_list : ArgList  - the argument list used to set the resource
 *	ang_cnt  : Cardinal - the number of arguments in the list
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
Initialize(Widget request, Widget set, ArgList arg_list, Cardinal *arg_cnt)
{
    XmColumnWidget rc = (XmColumnWidget) request,
                   sc = (XmColumnWidget) set;
    
    VerifyResources(rc, (XmColumnWidget) NULL, sc);

    if( rc->core.width == 0 )
    {
	sc->core.width = 2 * (rc->manager.shadow_thickness +
			      BBPart(rc)->margin_width);
    }
    if( rc->core.height == 0 )
    {
	sc->core.height = 2 * (rc->manager.shadow_thickness +
			       BBPart(rc)->margin_height);
    }
}

/*
 * Function:
 *	Destroy(widget)
 * Description:
 *	This function is called when an instance of the Column is being
 *	destroyed.  This function deallocates any memory allocated by the
 *	instance.
 * Input:
 *	widget : Widget - the widget being destroyed
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
Destroy(Widget widget)
{
    /* This space intentionally left blank */
}

/*
 * Function:
 *	Resize(widget)
 * Description:
 *	This function is called when an instance changes size.  This 
 *	function needs to adjust the childrens sizes and positions
 *	appropriately for the new size.
 * Input:
 *	widget : Widget - the widget that changed size.
 * Output:
 *	None.
 */
static void
Resize(Widget widget)
{
    WidgetClass    sc = XtSuperclass(widget);
    XmColumnWidget cw = (XmColumnWidget) widget;

    XtWidgetProc resize;
    
    _XmProcessLock(); 
    resize = *sc->core_class.resize;
    _XmProcessUnlock();
    (* resize) (widget);

    Layout(cw, NULL, NULL, -1, -1);

    XmColumn_resize_done(cw) = True;
}

/*
 * Function:
 *	SetValues(current, request, set, arg_list, arg_cnt)
 * Description:
 *	This function is called when the user changes the resource
 *	values for the column.  This function adjusts the columns
 *	appearance and behavior based on the new resource settings.
 * Input:
 *	current  : Widget  - the current resource values for the widget
 *	request  : Widget  - the requested resource values for the widget
 *	set      : Widget  - the new resource values for the widget
 *	arg_list : ArgList - the argument list used to change the resource
 *			     values
 *	arg_cnt  :Cardinal - the number of arguments
 * Output:
 *	Boolean - True if the Column needs redisplayed, else False.
 */
/* ARGSUSED */
static Boolean
SetValues(Widget current, Widget request, Widget set, ArgList arg_list,
	  Cardinal *arg_cnt)
{
    XmColumnWidget cc = (XmColumnWidget) current,
                   cs = (XmColumnWidget) set;
    Boolean        request_size = False,
                   relayout = False;
    WidgetList     kid, kids = cs->composite.children;
    Cardinal       n, i, kidCnt = cs->composite.num_children;
    Arg            args[10];

    VerifyResources((XmColumnWidget) request, cc, cs);

    if( XmColumn_item_spacing(cc) != XmColumn_item_spacing(cs) ||
        XmColumn_label_spacing(cc) != XmColumn_label_spacing(cs) ||
        XmColumn_distribution(cc) != XmColumn_distribution(cs) ||
        XmColumn_orientation(cc) != XmColumn_orientation(cs) ||
        cc->manager.shadow_thickness != cs->manager.shadow_thickness ||
        BBPart(cc)->margin_width != BBPart(cs)->margin_width ||
        BBPart(cc)->margin_height != BBPart(cs)->margin_height)
    {
	request_size = True;
    }

    if( XmColumn_default_fill_style(cc) != XmColumn_default_fill_style(cs) 
#if 0	/* POSITION HANDLING */
	|| XmColumn_default_label_position(cc) != XmColumn_default_label_position(cs) 
#endif
	)
    {
	relayout = True;
    }

    n = 0;
    if( cc->core.background_pixel != cs->core.background_pixel )
    {
	XtSetArg(args[n], XmNbackground, cs->core.background_pixel); n++;
    }
    if( cc->manager.foreground != cs->manager.foreground )
    {
	XtSetArg(args[n], XmNforeground, cs->manager.foreground); n++;
    }

    for( i = 0, kid = kids; i < kidCnt; ++i, ++kid )
    {
	if( (*kid) == NULL || (*kid)->core.being_destroyed ||
	    XiC(*kid)->label_widget == NULL ) continue;

	XtSetValues(XiC(*kid)->label_widget, args, n);
    }

    if( BBPart(cc)->label_font_list !=
            BBPart(cs)->label_font_list )
    {
	for( i = 0, kid = kids; i < kidCnt; ++i, ++kid )
	{
	    if( (*kid) == NULL || (*kid)->core.being_destroyed ||
	       XiC(*kid)->label_widget == NULL ) continue;

	    if( XiC(*kid)->label_font_list == NULL )
	    {
		XtVaSetValues(XiC(*kid)->label_widget,
			      XmNrenderTable,
			      BBPart(cs)->label_font_list,
			      NULL);
	    }
	}
    }

    if( XmColumn_default_label_alignment(cc) !=
            XmColumn_default_label_alignment(cs) )
    {
	for( i = 0, kid = kids; i < kidCnt; ++i, ++kid )
	{
	    if( (*kid) == NULL || (*kid)->core.being_destroyed ||
	       XiC(*kid)->label_widget == NULL ) continue;

	    if( XiC(*kid)->label_alignment == XmALIGNMENT_UNSPECIFIED )
	    {
		XtVaSetValues(XiC(*kid)->label_widget,
			      XmNalignment,
			      XmColumn_default_label_alignment(cs),
			      NULL);
	    }
	}
    }

    if( request_size )
    {
	Dimension width, height;

	XmColumn_resize_done(cs) = False;
	CalcSize(cs, NULL, NULL, False, &width, &height);
	if( XtMakeResizeRequest((Widget) cs, width, height, &width,
			&height) == XtGeometryAlmost )
	{
	    XmColumn_resize_done(cs) = False;
	    XtMakeResizeRequest((Widget) cs, width, height, NULL, NULL);
	}
	
	relayout = !XmColumn_resize_done(cs);
    }

    if( relayout )
    {
	Resize((Widget) cs);
    }

    return( False );
}

/*
 * Function:
 *	QueryGeometry(widget, request, allowed)
 * Description:
 *	This function is called when someone wants to know how the Column
 *	would react to a specific geometry or when someone wants to know
 *	what size the Column wants to be.
 * Input:
 *	widget  : Widget            - the column widget
 *	request : XtWidgetGeometry* - the requested widget geometry
 *	allowed : XtWidgetGeometry* - the geometry column is will to accept
 * Output:
 *	XtWidgetResult - the columns response to the geometry request
 */
static XtGeometryResult
QueryGeometry(Widget widget, XtWidgetGeometry *request,
	      XtWidgetGeometry *wanted)
{
    XmColumnWidget   cw = (XmColumnWidget) widget;
    XtGeometryResult result;
    Dimension        width, height;

    /*
     * Lets start by calling this handly dandy function to calculate
     * the geometry we want to be.
     */
    CalcSize(cw, NULL, NULL, False, &width, &height);

    /*
     * Now lets see if the caller requested anything and if not
     * lets give him our prefered geometry.
     */
    if( request->request_mode == 0 )
    {
	wanted->request_mode = CWWidth | CWHeight;
	wanted->width = width;
	wanted->height = height;

	if( width == XtWidth(cw) && height == XtHeight(cw) )
	{
	    return( XtGeometryNo );
	}
	return( XtGeometryAlmost );
    }

    *wanted = *request;
    if( request->request_mode & CWWidth )
    {
	if( request->width < width )
	{
	    wanted->width = width;
	}
    }

    if( request->request_mode & CWHeight )
    {
	if( request->height < height )
	{
	    wanted->height = height;
	}
    }

    /*
     * Now we have set everything in our return structure to what we
     * want it to be.  Now all that is left is to come up with the
     * correct return result.  The return result is something like.
     *
     * o request == wanted and wanted != real	-> XtGeometryYes
     * o request == wanted and wanted == real	-> XtGeometryNo
     * o request != wanted and wanted != real	-> XtGeometryAlmost
     * o request != wanted and wanted == real   -> XtGeometryNo
     */

    /*
     * Lets first see if request == wanted
     */
    if( CompareGeometryToWidget(wanted, (Widget) cw) )
    {
	result = XtGeometryNo;
    }
    else
    {
	if( CompareGeometry(request, wanted) )
	{
	    result = XtGeometryYes;
	}
	else
	{
	    result = XtGeometryNo;
	}
    }

    return( result );
}

/*
 * Function:
 *	GeometryManager(widget, request, allowed)
 * Description:
 *	This function is called when a child of the Column would like
 *	to change size.  This function reacts to the child's request.
 * Input:
 *	widget  : Widget            - the child requesting the change
 *	request : XtWidgetGeometry* - the requested widget geometry
 *	allowed : XtWidgetGeometry* - the geometry column is will to accept
 * Output:
 *	XtWidgetResult - the columns response to the geometry request
 */
static XtGeometryResult
GeometryManager(Widget widget, XtWidgetGeometry *request,
		XtWidgetGeometry *allowed)
{
    XmColumnWidget   cw = (XmColumnWidget) XtParent(widget);
    Dimension        width, height, width_return, height_return;
    XtGeometryResult result;
    Boolean          equal;

    /*
     * Now being the mean manager that we are, we are only going to 
     * allow our children to change geometry parts the affect their
     * size.  i.e. we will not even discuss with them their position,
     * this is mainly because we do not want to deal with it.
     */
    
    *allowed = *request;
    allowed->request_mode = request->request_mode =
	(request->request_mode & ~(CWX | CWY));

    /*
     * Now lets see what this child wants to change.
     */
    if( request->request_mode & CWWidth )
    {
	allowed->width = request->width;
    }
    else
    {
	allowed->width = XiC(widget)->request_width;
    }

    if( request->request_mode & CWHeight )
    {
	allowed->height = request->height;
    }
    else
    {
	allowed->height = XiC(widget)->request_height;
    }

    if( request->request_mode & CWBorderWidth )
    {
	allowed->border_width = request->border_width;
    }
    else
    {
	allowed->border_width = XtBorderWidth(widget);
    }

    /*
     * Now that we know what size our child want to be lets see
     * how that effects the geometry we want to be.
     */
    CalcSize(cw, widget, allowed, False, &width, &height);

    /*
     * Now that we know that size that we want to be, lets ask our
     * parent and see what they have to say.
     */
    if( request->request_mode & XtCWQueryOnly )
    {
	XtWidgetGeometry req, alw;

	req.request_mode = CWWidth | CWHeight | XtCWQueryOnly;
	req.width = width;
	req.height = height;

	width = XtWidth(cw);
	height = XtHeight(cw);
	switch( XtMakeGeometryRequest((Widget) cw, &req, &alw) )
	{
	case XtGeometryYes:
	    return( XtGeometryYes );
	    break;
	case XtGeometryAlmost:
	    if( alw.request_mode & CWWidth ) width = alw.width;
	    if( alw.request_mode & CWHeight ) height = alw.height;
	case XtGeometryNo:
	default:
	    Layout(cw, widget, allowed, width, height);

	    allowed->width = XiC(widget)->position.width;
	    allowed->height = XiC(widget)->position.height;
	    break;
	}
    }
    else
    {
	Dimension cur_width, cur_height;

	XiC(widget)->request_width = allowed->width;
	XiC(widget)->request_height = allowed->height;
	XmColumn_resize_done(cw) = False;
	
	cur_width = XtWidth(cw);
	cur_height = XtHeight(cw);
	switch( XtMakeResizeRequest((Widget) cw, width, height,
				    &width_return, &height_return) )
	{
	case XtGeometryYes:
	    /*
	     * It appears that our parent will has let us change to 
	     * the size that we want to be, so lets see if we need to
	     * call our resize procedure.
	     */
	    if( !XmColumn_resize_done(cw) ) Resize((Widget) cw);

	    Layout(cw, widget, allowed, width, height);
	    allowed->width = XiC(widget)->position.width;
	    allowed->height = XiC(widget)->position.height;
	    break;
	case XtGeometryAlmost:
	    cur_width = width_return;
	    cur_height = height_return;
	case XtGeometryNo:
	default:
	    Layout(cw, widget, allowed, cur_width, cur_height);

	    allowed->width = XiC(widget)->position.width;
	    allowed->height = XiC(widget)->position.height;
	    break;
	}
    }

    width = XtWidth(widget);
    height = XtHeight(widget);
    equal = CompareGeometryToWidget(allowed, widget);

    if( equal )
    {
	result = XtGeometryNo;
    }
    else
    {
	if( CompareGeometry(request, allowed) )
	{
	    result = XtGeometryYes;
	}
	else
	{
	    result = XtGeometryAlmost;
	}
    }

    if( result == XtGeometryYes )
    {
	Layout(cw, NULL, NULL, -1, -1);
    }

    return( result );
}

/*
 * Function:
 *	ChangeManaged(widget)
 * Description:
 *	This is called when one of the children of the column changes
 *	managed state.  This routine just takes care of this situation.
 * Input:
 *	widget : Widget - the column widget
 * Output:
 *	None.
 */
static void
ChangeManaged(Widget widget)
{
    static Boolean in = False;
    XmColumnWidget cw = (XmColumnWidget) widget;
    WidgetList     kid = cw->composite.children;
    Widget         label;
    Cardinal       i;
    Dimension      width, height;

    if( in ) return;

    in = True;

    for( i = 0; i < cw->composite.num_children; ++i, ++kid )
    {
	if( !XiValidChild(*kid) ) 
	{
	  if( (*kid) != NULL && !XtIsManaged(*kid) )
	    {	/* CR03731 */
	      if (XiC(*kid)->label_widget) {
		XtUnmanageChild(XiC(*kid)->label_widget);
	      }
	      XiC(*kid)->request_width = 0;
	      XiC(*kid)->request_height = 0;
	    }
	    continue; 
	}
	
	label = XiC(*kid)->label_widget;
	if( !XiC(*kid)->show_label )
	{
	    if( XtIsManaged(*kid) ) XtUnmanageChild(label);
	}
	else if( XtIsManaged(*kid) != XtIsManaged(label) )
	{
	    if( XtIsManaged(*kid) )
	    {
		XtManageChild(label);
	    }
	    else
	    {	
		XtUnmanageChild(label);
	    }
	}

	if( XiC(*kid)->request_width == 0 && XtIsManaged(*kid) )
	{
	    XiC(*kid)->request_width = XtWidth(*kid);
	    XiC(*kid)->request_height = XtHeight(*kid);
	}
	if( XtIsManaged(label) )
	{
	    if( XiC(label)->request_width == 0 )
	    {
#if 0
		XiC(label)->request_width = XtWidth(label);
		XiC(label)->request_height = XtHeight(label);
#else
		{
		/* Unfortunately, XtWidth() and XtHeight() may not be valid in
		** this case. The request_width and request_height values are
		** used both to indicate real requested size and also, when 0,
		** to indicate a label with particular geometry needs. 
		** However, if the code goes through ConstraintSetValues (in
		** code generated by the Xcessory tools, constraint resources
		** are set via set-values after widget creation) first, the 
		** sizes are 0 and are then set to 1 in VerticalLayout; then
		** the code comes through here and updates the request values
		** from the real widths -- 1 -- which are then set back on the
		** widget as the geometry. The net result is that the labels
		** appear with width 1 (and correct height).
		**
		** Ideally we would cache the real initial requested value and
		** update from that value.
		**
		** For now, rather than storing those values, query the 
		** label locally for its preferences and use those; the result
		** should be that the size is set correctly (going through
		** CalcSize and then VerticalLayout).
		*/
		
    		    XtWidgetGeometry wants;
		    XtQueryGeometry(label, NULL, &wants);

		    if( wants.request_mode & CWWidth )
		    {
			XiC(label)->request_width = wants.width;
		    }
		    else
		    {
			XiC(label)->request_width = XtWidth(label);
		    }

		    if( wants.request_mode & CWHeight )
		    {
			XiC(label)->request_height = wants.height;
		    }
		    else
		    {
			XiC(label)->request_height = XtHeight(label);
		    }
		}
#endif
	    }
	}
	else
	{
	    XiC(label)->request_width = 0;
	    XiC(label)->request_height = 0;
	}
    }

    CalcSize(cw, NULL, NULL, False, &width, &height);

    if( XtMakeResizeRequest(widget, width, height, &width, &height) ==
        XtGeometryAlmost )
    {
	XtMakeResizeRequest(widget, width, height, NULL, NULL);
    }

    Layout(cw, NULL, NULL, -1, -1);

    in = False;
}

/*
 * Function:
 *	ConstraintInitialize(request, new_w, arg_list, arg_cnt)
 * Description:
 *	This function initializes the constraint record for a new child,
 *	this includes adding a label for each child.
 * Input:
 *	request  : Widget   - the requested resource values
 *	new_w      : Widget   - the new_w resource values (the new widget)
 *	arg_list : ArgList  - the argument used to create the widget
 *	arg_cnt  : Cardinal - the number of arguments
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
ConstraintInitialize(Widget request, Widget new_w, ArgList arg_list,
		     Cardinal *arg_cnt)
{
    static         Boolean label_widget = False;	/* STATIC DATA */
    XmColumnWidget cw = (XmColumnWidget) XtParent(new_w);
    XmBulletinBoardPart *bbpart;

	/* CR03562 CR02961 When ChangeManaged is bypassed, request width and height
	   are not set. The 2 line will prevent this assumption which sometimes
	   will case the widget size to have zero width/height */
#if 1
	/* Note! below fix problematic w.r.t. ChangeManaged code, and needs
	** revisiting; back out temporarily
	*/
	/*
	** It is possible that the widget will have a constraint resource set 
	** on it before the XmColumn itself is realized (ChangeManaged is
	** bypassed in that case), so that we enter the Layout code without
	** having the values request_width and request_height set from the
	** code in ChangeManaged. Rather than use 0 here, which gives poor
	** results when those values are used in XtConfigureWidget to set
	** the size, initialize them to reasonable default values.
	*/
	XiC(new_w)->request_width = XtWidth(new_w);
	XiC(new_w)->request_height = XtHeight(new_w);
#else
	XiC(new_w)->request_width = 0;
	XiC(new_w)->request_height = 0;
#endif

    XiC(new_w)->label_string = XmStringCopy(XiC(new_w)->label_string);
    if( label_widget )
    {
	XiC(new_w)->label_alignment = XmALIGNMENT_UNSPECIFIED;
#if 0	/* POSITION HANDLING */
	XiC(new_w)->label_position = XiLABEL_POSITION_UNSPECIFIED;
#endif
	XiC(new_w)->label_type = XmSTRING;
	XiC(new_w)->label_pixmap = XmUNSPECIFIED_PIXMAP;
	XiC(new_w)->label_string = (XmString) NULL;
	XiC(new_w)->label_widget = (Widget) NULL;
	XiC(new_w)->show_label = False;
    }
    else
    {
	Arg    args[64];
	int    nargs;
	char   buf[256];
	Widget label;
	XmFontList lfont;

	VerifyConstraints(request, NULL, new_w);
	
	if( strlen(XtName(new_w)) > 240 )
	{
	    strncpy(buf, XtName(new_w), 240);
	    buf[240] = '\0';
	    strcat(buf, "_label");
	}
	else
	{
	    strcpy(buf, XtName(new_w));
	    strcat(buf, "_label");
	}

	label_widget = True;

	lfont = XmColumnC_label_font_list(new_w);
	bbpart = BBPart(XtParent(new_w));
	if(lfont == NULL)
	    lfont = bbpart->label_font_list;

	nargs = 0;
	XtSetArg(args[nargs], XmNmarginWidth,        0); nargs++;
	XtSetArg(args[nargs], XmNmarginHeight,       0); nargs++;
	XtSetArg(args[nargs], XmNmarginTop,          0); nargs++;
	XtSetArg(args[nargs], XmNmarginBottom,       0); nargs++;
	XtSetArg(args[nargs], XmNmarginLeft,         0); nargs++;
	XtSetArg(args[nargs], XmNmarginRight,        0); nargs++;
	XtSetArg(args[nargs], XmNshadowThickness,    0); nargs++;
	XtSetArg(args[nargs], XmNhighlightThickness, 0); nargs++;
	XtSetArg(args[nargs], XmNtraversalOn,      False); nargs++;
	XtSetArg(args[nargs], XmNlabelType,   XiC(new_w)->label_type); nargs++;
	XtSetArg(args[nargs],
		 XmNlabelString, XiC(new_w)->label_string); nargs++;
	XtSetArg(args[nargs],
		 XmNlabelPixmap, XiC(new_w)->label_pixmap); nargs++;
	XtSetArg(args[nargs], XmNalignment,   XiAlignment(new_w));     nargs++;
	XtSetArg(args[nargs], XmNrenderTable,    lfont);          nargs++;
	XtSetArg(args[nargs], XmNrecomputeSize, True);                 nargs++;
	XtSetArg(args[nargs], XmNforeground,  cw->manager.foreground); nargs++;
	XtSetArg(args[nargs],
		 XmNbackground,  cw->core.background_pixel); nargs++;
	label = XtCreateWidget(buf, xmLabelWidgetClass, (Widget) cw,
		       args, nargs);
	XiC(new_w)->label_widget = label;

	XtAddCallback(label, XmNdestroyCallback,
		      XmColumnLabelDestroyedCallback, (XtPointer) new_w);
	XiC(label)->label_alignment = XmALIGNMENT_UNSPECIFIED;
#if 0	/* POSITION HANDLING */
	XiC(label)->label_position = XiLABEL_POSITION_UNSPECIFIED;
#endif
	XiC(label)->label_type = XmSTRING;
	XiC(label)->label_pixmap = XmUNSPECIFIED_PIXMAP;
	XiC(label)->label_string = (XmString) NULL;
	XiC(label)->label_widget = (Widget) NULL;
	XiC(label)->show_label = False;
	label_widget = False;
    }
}

/*
 * Function:
 *	ConstraintSetValues(current, request, new_w, arg_list, arg_cnt)
 * Description:
 *	This function is called when the user changes an attribute of
 * 	one of the columns children.  This routine reacts to the change.
 * Input:
 *	current  : Widget   - the current state of the child
 *	request  : Widget   - the request state of the child
 *	new_w      : Widget   - the child with the requested changes
 *	arg_list : ArgList  - the argument that modified the child
 *	arg_cnt  : Cardinal - the number of argument
 * Output:
 *	Boolean - True if the child needs to be redisplayed, else False.
 */
/* ARGSUSED */
static Boolean
ConstraintSetValues(Widget current, Widget request, Widget new_w,
		    ArgList arg_list, Cardinal *arg_cnt)
{
    XmColumnWidget         cw = (XmColumnWidget) XtParent(new_w);
    XmColumnConstraintPart *cc = XiC(current),
                           *sc = XiC(new_w);
    Boolean                relayout = False;
    Arg                    args[10];
    Cardinal               i = 0;

    if( XiC(new_w)->label_widget == NULL ) return( False );

    VerifyConstraints(request, current, new_w);

    if( 
#if 0	/* POSITION HANDLING */
	cc->label_position != sc->label_position ||
#endif
        cc->fill_style != sc->fill_style ||
        cc->show_label != sc->show_label )
    {
	relayout = True;
    }

    if( cc->label_font_list != sc->label_font_list )
    {
	XmFontList lfont = XmColumnC_label_font_list(new_w);
	if(lfont == NULL)
	    lfont = BBPart(XtParent(new_w))->label_font_list;
	XtSetArg(args[i], XmNrenderTable, lfont); ++i;
    }

    if( cc->label_alignment != sc->label_alignment )
    {
	XtSetArg(args[i], XmNalignment, XiAlignment(new_w)); ++i;
    }

    if( cc->label_string != sc->label_string )
    {
	XmStringFree(cc->label_string);
	sc->label_string = XmStringCopy(sc->label_string);
	XtSetArg(args[i], XmNlabelString, sc->label_string); ++i;
    }

    if( cc->label_pixmap != sc->label_pixmap )
    {
	XtSetArg(args[i], XmNlabelPixmap, sc->label_pixmap); ++i;
    }

    if( cc->label_type != sc->label_type )
    {
	XtSetArg(args[i], XmNlabelType, sc->label_type); ++i;
    }

    if( i >  0 ) XtSetValues(sc->label_widget, args, i);

    XmColumn_resize_done(cw) = False;
    if( cc->show_label != sc->show_label )
    {
	if( sc->show_label )
	{
	    XtManageChild(sc->label_widget);
	}
	else
	{
	    XtUnmanageChild(sc->label_widget);
	}
    }
    
    if( relayout && !XmColumn_resize_done(cw) )
    {
	Layout(cw, NULL, NULL, -1, -1);
    }

    return( False );
}

/*
 * Function:
 *	ConstraintDestroy(widget)
 * Description:
 *	This function is called to deallocate any resources allocated by
 *	the constraint record.
 * Input:
 *	widget : Widget - the widget being destroyed.
 * Output:
 *	None.
 */
static void
ConstraintDestroy(Widget widget)
{
    XmStringFree(XiC(widget)->label_string);
    if( XiC(widget)->label_widget != NULL )
    {
	XtRemoveCallback(XiC(widget)->label_widget, XmNdestroyCallback,
			 XmColumnLabelDestroyedCallback, (XtPointer) widget);
	XtDestroyWidget(XiC(widget)->label_widget);
	XiC(widget)->label_widget = NULL;
    }
}

/*
 * Function:
 *      ConstraintGetValues
 * Description:
 *      The constraint get_values_hook method.  It makes copies of the 
 *      XmNentryLabelString values to prevent returning internal
 *      XmString data.
 * Input:
 *      w - The child widget
 *      args - Array of Arg structures
 *      num_args - Number of entries in args
 * Output:
 *      none (other than the silently copies XmString value)
 */
static void
ConstraintGetValues(Widget w, ArgList args, Cardinal *num_args)
{
    XrmQuark                    quark;
    int                         i;
    
    quark = XrmStringToQuark(XmNentryLabelString);
    for (i = 0; i < ((int) *num_args); i++)
    {
        if (quark == XrmStringToQuark(args[i].name))
        {
            args[i].value =
		(XtArgVal) XmStringCopy(XmColumnC_label_string(w));
            break;
        }
    }
}

static int
CompareISOLatin1 (char *first, char *second)
{
    register unsigned char *ap, *bp;

    for (ap = (unsigned char *) first, bp = (unsigned char *) second;
         *ap && *bp; ap++, bp++) {
        register unsigned char a, b;

        if ((a = *ap) != (b = *bp)) {
            /* try lowercasing and try again */

            if ((a >= XK_A) && (a <= XK_Z))
		a += (XK_a - XK_A);
            else if ((a >= XK_Agrave) && (a <= XK_Odiaeresis))
              a += (XK_agrave - XK_Agrave);
            else if ((a >= XK_Ooblique) && (a <= XK_Thorn))
              a += (XK_oslash - XK_Ooblique);

            if ((b >= XK_A) && (b <= XK_Z))
              b += (XK_a - XK_A);
            else if ((b >= XK_Agrave) && (b <= XK_Odiaeresis))
              b += (XK_agrave - XK_Agrave);
            else if ((b >= XK_Ooblique) && (b <= XK_Thorn))
              b += (XK_oslash - XK_Ooblique);

            if (a != b) break;
        }
    }
    return (((int) *bp) - ((int) *ap));
}

/*
 * Function:
 *	done
 * Description:
 *	This macro is used by the resource conversion routines and
 *	simply assigns the value and returns the correct result.
 */
#define done(type, value) 				\
    {							\
	if( to->addr != NULL )				\
	{						\
	    if( to->size < sizeof(type) )		\
	    {						\
		to->size = sizeof(type);		\
		return( False );			\
	    }						\
	    *(type*)(to->addr) = (value);		\
	}						\
	else						\
	{						\
	    static type static_val;			\
	    static_val = (value);			\
	    to->addr = (XtPointer) &static_val;		\
	}						\
	to->size = sizeof(type);			\
	return( True );					\
    }

#if 0	/* POSITION HANDLING */
/*
 * Function:
 *	CvtStringToLabelPosition(dpy, args, arg_cnt, from, to, data)
 * Description:
 *	This function converts a string representation of the representation
 *	type XmRLabelPosition to an actual value.
 * Input:
 *	dpy     : Display   - unused
 *	args    : XrmValue* - unused
 *	arg_cnt : Cardinal  - unused
 *	from    : XrmValue* - contains the string representation of the value
 *	to      : XrmValue* - returns the actual value
 *	data    : XtPointer - unused
 * Output:
 *	Boolean - True if the conversion was successful else False.
 */
static Boolean
CvtStringToLabelPosition(Display *dpy, XrmValue *args, Cardinal *arg_cnt,
			 XrmValue *from, XrmValue *to, XtPointer data)
{
    unsigned char result = XiLABEL_POSITION_LEFT;
    String        str = (String) (from->addr);

    if( CompareISOLatin1(str, "label_position_unspecified") == 0 ||
        CompareISOLatin1(str, "unspecified") == 0 )
    {
	result = XiLABEL_POSITION_UNSPECIFIED;
    }
    else if( CompareISOLatin1(str, "label_position_left") == 0 ||
	     CompareISOLatin1(str, "left") == 0 )
    {
	result = XiLABEL_POSITION_LEFT;
    }
    else if( CompareISOLatin1(str, "label_position_right") == 0 ||
	     CompareISOLatin1(str, "right") == 0 )
    {
	result = XiLABEL_POSITION_RIGHT;
    }
    else if( CompareISOLatin1(str, "label_position_top") == 0 ||
	     CompareISOLatin1(str, "top") == 0 )
    {
	result = XiLABEL_POSITION_TOP;
    }
    else if( CompareISOLatin1(str, "label_position_bottom") == 0 ||
	     CompareISOLatin1(str, "bottom") == 0 )
    {
	result = XiLABEL_POSITION_BOTTOM;
    }
    else if( CompareISOLatin1(str, "label_position_center") == 0 ||
	     CompareISOLatin1(str, "CENTER") == 0 )
    {
	result = XiLABEL_POSITION_CENTER;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, from->addr, XmRLabelPosition);
	return( False );
    }

    done(unsigned char, result);
}
#endif

/*
 * Function:
 *	CvtStringToXiAlignment(dpy, args, arg_cnt, from, to, data)
 * Description:
 *	This function converts a string representation of the representation
 *	type XmRXnAlignment to an actual value.
 * Input:
 *	dpy     : Display   - unused
 *	args    : XrmValue* - unused
 *	arg_cnt : Cardinal  - unused
 *	from    : XrmValue* - contains the string representation of the value
 *	to      : XrmValue* - returns the actual value
 *	data    : XtPointer - unused
 * Output:
 *	Boolean - True if the conversion was successful else False.
 */
/* ARGSUSED */
static Boolean
CvtStringToXiAlignment(Display *dpy, XrmValue *args, Cardinal *arg_cnt,
		       XrmValue *from, XrmValue *to, XtPointer data)

{
    unsigned char result = XmALIGNMENT_CENTER;
    String        str = (String) (from->addr);

    if( CompareISOLatin1(str, "alignment_unspecified") == 0 ||
        CompareISOLatin1(str, "unspecified") == 0 )
    {
	result = XmALIGNMENT_UNSPECIFIED;
    }
    else if( CompareISOLatin1(str, "alignment_beginning") == 0 ||
	     CompareISOLatin1(str, "beginning") == 0 )
    {
	result = XmALIGNMENT_BEGINNING;
    }
    else if( CompareISOLatin1(str, "alignment_center") == 0 ||
	     CompareISOLatin1(str, "center") == 0 )
    {
	result = XmALIGNMENT_CENTER;
    }
    else if( CompareISOLatin1(str, "alignment_end") == 0 ||
	     CompareISOLatin1(str, "end") == 0 )
    {
	result = XmALIGNMENT_END;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, from->addr, XmRXmAlignment);
	return( False );
    }

    done(unsigned char, result);
}

/*
 * Function:
 *	CvtStringToFillStyle(dpy, args, arg_cnt, from, to, data)
 * Description:
 *	This function converts a string representation of the representation
 *	type XmRFillStyle to an actual value.
 * Input:
 *	dpy     : Display   - unused
 *	args    : XrmValue* - unused
 *	arg_cnt : Cardinal  - unused
 *	from    : XrmValue* - contains the string representation of the value
 *	to      : XrmValue* - returns the actual value
 *	data    : XtPointer - unused
 * Output:
 *	Boolean - True if the conversion was successful else False.
 */
/* ARGSUSED */
static Boolean
CvtStringToFillStyle(Display *dpy, XrmValue *args, Cardinal *arg_cnt,
		     XrmValue *from, XrmValue *to, XtPointer data)
{
    unsigned char result = XmFILL_UNSPECIFIED;
    String        str = (String) (from->addr);

    if( CompareISOLatin1(str, "fill_unspecified") == 0 ||
        CompareISOLatin1(str, "unspecified") == 0 )
    {
	result = XmFILL_UNSPECIFIED;
    }
    else if( CompareISOLatin1(str, "fill_flush") == 0 ||
	     CompareISOLatin1(str, "flush") == 0 )
    {
	result = XmFILL_FLUSH;
    }
    else if( CompareISOLatin1(str, "fill_ragged") == 0 ||
	     CompareISOLatin1(str, "ragged") == 0 )
    {
	result = XmFILL_RAGGED;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, from->addr, XmRFillStyle);
	return( False );
    }

    done(unsigned char, result);
}

/*
 * Function:
 *	CvtStringToDistribution(dpy, args, arg_cnt, from, to, data)
 * Description:
 *	This function converts a string representation of the representation
 *	type XmRDistribution to an actual value.
 * Input:
 *	dpy     : Display   - unused
 *	args    : XrmValue* - unused
 *	arg_cnt : Cardinal  - unused
 *	from    : XrmValue* - contains the string representation of the value
 *	to      : XrmValue* - returns the actual value
 *	data    : XtPointer - unused
 * Output:
 *	Boolean - True if the conversion was successful else False.
 */
/* ARGSUSED */
static Boolean
CvtStringToDistribution(Display *dpy, XrmValue *args, Cardinal *arg_cnt,
			XrmValue *from, XrmValue *to, XtPointer data)
{
    unsigned char result = XmDISTRIBUTE_TIGHT;
    String        str = (String) (from->addr);

    if( CompareISOLatin1(str, "distribute_tight") == 0 ||
        CompareISOLatin1(str, "tight") == 0 )
    {
	result = XmDISTRIBUTE_TIGHT;
    }
    else if( CompareISOLatin1(str, "distribute_spread") == 0 ||
	     CompareISOLatin1(str, "spread") == 0 )
    {
	result = XmDISTRIBUTE_SPREAD;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, from->addr, XmRDistribution);
	return( False );
    }

    done(unsigned char, result);
}

/*
 * Function:
 *	VerifyResources(request, current, new_w)
 * Description:
 *	This function verifies the values for the Column's resource in
 *	"new_w" resetting them to the previous or default values if an
 *	invalid resource value was set.
 * Input:
 *	request	: XmColumnWidget - the requested setting for the widget
 *	current : XmColumnWidget - the current setting for the widget
 *	new_w     : XmColumnWidget - the setting for the widget
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
VerifyResources(XmColumnWidget request, XmColumnWidget current, 
		XmColumnWidget new_w)
{
    Boolean  reset;

    if( BBPart(new_w)->label_font_list == NULL )
    {
	BBPart(new_w)->label_font_list =
	    XmeGetDefaultRenderTable((Widget) new_w, XmLABEL_FONTLIST);
    }

    reset = False;
#if 0	/* POSITION HANDLING */
    switch( XmColumn_default_label_position(new_w) )
    {
    case XiLABEL_POSITION_CENTER:
    case XiLABEL_POSITION_LEFT:
    case XiLABEL_POSITION_RIGHT:
    case XiLABEL_POSITION_TOP:
    case XiLABEL_POSITION_BOTTOM:
	break;
    case XiLABEL_POSITION_UNSPECIFIED:
	XmeWarning((Widget) new_w),
			"The illegal resource value \"XiLABEL_POSITION_UNSPECIFIED\" was assigned to the resource XmNDefaultLabelPosition");
	reset = True;
	break;
    default:
	XmeWarning((Widget) new_w,
			"An illegal resource value was assigned to the resource XmNDefaultLabelPosition");
	reset = True;
	break;
    }    

    if( reset )
    {
	XmColumn_default_label_position(new_w) =
	    (current != NULL
	     ? XmColumn_default_label_position(current)
	     : DEFAULT_POSITION);
    }
#endif

    reset = False;
    switch( XmColumn_default_label_alignment(new_w) )
    {
    case XmALIGNMENT_BEGINNING:
    case XmALIGNMENT_CENTER:
    case XmALIGNMENT_END:
	break;
    case XmALIGNMENT_UNSPECIFIED:
	XmeWarning((Widget) new_w,
			"The illegal resource value \"XmALIGNMENT_UNSPECIFIED\" was assigned to the resource XmNdefaultEntryLabelAlignment");
	reset = True;
	break;
    default:
	XmeWarning((Widget) new_w,
			"An illegal resource value was assigned to the resource XmNdefaultEntryLabelAlignment");
	reset = True;
	break;
    }

    if( reset )
    {
	XmColumn_default_label_alignment(new_w) =
	    (current != NULL
	     ? XmColumn_default_label_alignment(current)
	     : DEFAULT_ALIGNMENT);
    }

    reset = False;
    switch( XmColumn_orientation(new_w) )
    {
    case XmHORIZONTAL:
    case XmVERTICAL:
	break;
    default:
	XmeWarning((Widget) new_w,
			"An illegal resource value was assigned to the resource XmNorientation");
	reset = True;
	break;
    }

    if( reset )
    {
	XmColumn_orientation(new_w) =
	    (current != NULL
	     ? XmColumn_orientation(current)
	     : DEFAULT_ORIENTATION);
    }
}

/*
 * Function:
 *	Layout(cw, child, child_size, col_width, col_height)
 * Description:
 *	This is simply a launcher routine.  This routine passes control
 *	to the appropriate layout routine depending on the orientation
 *	of the column.
 * Input:
 *	cw         : XmColumnWidget -   the column to layout
 *	child      : Widget            - A childs whose geometry is specified
 *	child_size : XtWidgetGeometry* - the specified child geometry
 *	col_width  : int               - a specified width for the column
 *	col_height : int               - a specified height for the column
 * Output:
 *	None.
 */
static void
Layout(XmColumnWidget cw, Widget child, XtWidgetGeometry *child_size,
       int col_width, int col_height)
{
    if (XmColumn_orientation(cw) == XmHORIZONTAL)
    {
	HorizontalLayout(cw, child, child_size, col_width, col_height);
    }
    else
    {
	VerticalLayout(cw, child, child_size, col_width, col_height);
    }
}

/*
 * Function:
 *	HorizontalLayout(cw, child, child_size, col_witdh, col_height)
 * Description:
 *	This routine handles the horizontal layout for the column widget
 * Input:
 *	cw         : XmColumnWidget -   the column to layout
 *	child      : Widget            - A childs whose geometry is specified
 *	child_size : XtWidgetGeometry* - the specified child geometry
 *	col_width  : int               - a specified width for the column
 *	col_height : int               - a specified height for the column
 * Output:
 *	None.
 */
static void
HorizontalLayout(XmColumnWidget cw, Widget child,
		 XtWidgetGeometry *child_size, int col_width, int col_height)
{
    /* Do the Horizontal Layout, Baby! */
    WidgetList	kids = cw->composite.children, kid;
    Widget	label;
    Cardinal	i, kidCnt = cw->composite.num_children;
    Position	x, y;
    int		cWidth, cBorder, cbWidth, lWidth, valid, space;
    Dimension	fillHeight;
    int		ispace = (int)XmColumn_item_spacing(cw);
    int 	kidSpace;
    
    if( col_width < 0 ) col_width = XtWidth(cw);
    if( col_height < 0 ) col_height = XtHeight(cw);

    fillHeight = col_height - 2 * (cw->manager.shadow_thickness +
				   BBPart(cw)->margin_height);

    
    for( i = 0, kid = kids, lWidth = 0, cbWidth = 0, valid = 0,
	 space = 0, kidSpace = 0; i < kidCnt; ++i, ++kid )
    {
	XiC(*kid)->position.x = XiC(*kid)->position.y = 0;
	if( *kid == child )
	{
	    XiC(*kid)->position.width = child_size->width;
	    XiC(*kid)->position.height = child_size->height;
	}
	else
	{
	    XiC(*kid)->position.width = XiC(*kid)->request_width;
	    XiC(*kid)->position.height = XiC(*kid)->request_height;
	}

	if( !XiValidChild(*kid) ) continue;
	valid++;

	if( *kid == child )
	    cbWidth += child_size->width + 2*child_size->border_width;
	else
	    cbWidth += XiC(*kid)->request_width + 2*XtBorderWidth(*kid);

	if( !XiC(*kid)->show_label ) continue;

	space += XmColumn_label_spacing(cw);
	kidSpace++;

	label = XiC(*kid)->label_widget;
	if( label == child )
		lWidth += child_size->width;
	else
		lWidth += XiC(label)->request_width;
    }

    x = cw->manager.shadow_thickness + BBPart(cw)->margin_width;
    if( valid > 0 && (x + lWidth + space + cbWidth + ispace*(valid-1) + x  > col_width ) )
    {
	/*
	 * First try to shrink labelSpacing, then itemSpacing, otherwise clip.
	 */
	int have = (col_width - 2 * x),
	    want = lWidth + space + ispace*(valid-1) + cbWidth,
	    diff = want - have;

	if ( space - diff > 1)
		{
		space -= diff;
		}
	else
	{
		if (0 != space)
			space = kidSpace;
	    	want = lWidth + space + ispace*(valid-1) + cbWidth;	
	    	diff = want - have;

		if (ispace*(valid-1) - diff > 1)
			ispace = (ispace*(valid-1)-diff)/(valid-1);
		else
		{
			if (0 != ispace)
				ispace = 1;	
		}
	}
    }
    if (0==kidSpace) kidSpace = 1; 
    space /= kidSpace;

    /*
     * Calculating the widths for the various kids is a one shot, so lets
     * first walk through the kids and calculate all the width.
     */
    for( kid = kids, i = 0; i < kidCnt; ++i, ++kid )
    {
	int mySpace;
	if( !XiValidChild(*kid) ) continue;
	
	label = XiC(*kid)->label_widget;
	XiC(label)->position.width = XtWidth(label);
        if( XiC(*kid)->show_label )
		{
		lWidth = XtWidth(label);
		mySpace = space;
		}
	else 
		{
		lWidth = 0;
		mySpace = 0;
		}
	if (LayoutIsRtoLM(cw))
	    XiC(label)->position.x = col_width - x - lWidth;
	else
	    XiC(label)->position.x = x;

	/* First, let's calculate the kid's X-position */
	if( *kid == child )
		cWidth = XiC(*kid)->position.width = child_size->width;
	else
		cWidth = XiC(*kid)->position.width = XiC(*kid)->request_width;
	if (LayoutIsRtoLM(cw))
	    XiC(*kid)->position.x = col_width - (x + lWidth + space) - cWidth;
	else
	    XiC(*kid)->position.x = x + lWidth + space;
	if( child == *kid )
	    cBorder = child_size->border_width;
	else
	    cBorder = XtBorderWidth(*kid);
	x += lWidth + mySpace + cWidth + ispace + 2*cBorder; 

	/* Now, let's calculate the kid's Y-position */
	y = cw->manager.shadow_thickness + BBPart(cw)->margin_height;

	XiC(label)->position.y += y;
	XiC(*kid)->position.y += y;

	/* If XmNfillStyle == XmFILL_FLUSH, adjust height to same as column */
	if (XiFill(*kid) == XmFILL_FLUSH)
	{
	    XiC(label)->position.height = fillHeight;
	    XiC(*kid)->position.height = fillHeight;
	}
    }

    if( child == NULL )
    {
	for( i = 0, kid = kids; i < kidCnt; ++i, ++kid )
	{
	    if( !XiValidChild(*kid) ) continue;

	    label = XiC(*kid)->label_widget;

	    if( XiC(*kid)->show_label ) {
	      XtConfigureWidget(label, XiC(label)->position.x,
				XiC(label)->position.y,
				XiC(label)->position.width,
				XiC(*kid)->position.height, 0);
	    }

	    XtConfigureWidget(*kid, XiC(*kid)->position.x,
			      XiC(*kid)->position.y,
			      XiC(*kid)->position.width,
			      XiC(*kid)->position.height,
			      XtBorderWidth(*kid));
	}
    }
}

/*
 * Function:
 *	VerticalLayout(cw, child, child_size, col_witdh, col_height)
 * Description:
 *	This routine handles the vertical layout for the column widget
 * Input:
 *	cw         : XmColumnWidget -   the column to layout
 *	child      : Widget            - A childs whose geometry is specified
 *	child_size : XtWidgetGeometry* - the specified child geometry
 *	col_width  : int               - a specified width for the column
 *	col_height : int               - a specified height for the column
 * Output:
 *	None.
 */
static void
VerticalLayout(XmColumnWidget cw, Widget child, XtWidgetGeometry *child_size,
	       int col_width, int col_height)
{
    WidgetList kids = cw->composite.children, kid;
    Widget     label;
    Cardinal   i, kidCnt = cw->composite.num_children, j;
    Position   x, y;
    int        cWidth, cMaxWidth, cMinWidth, cHeight, cBorder, cbWidth, cbHeight,
               lWidth, lHeight, cnt, hExtra, hEach =0 , hLeft = 0, valid, space;
    Dimension  width, height;
    Boolean    change, stretch;

    if( col_width < 0 ) col_width = XtWidth(cw);
    if( col_height < 0 ) col_height = XtHeight(cw);

    CalcSize(cw, NULL, NULL, False, &width, &height);
    for( i = 0, kid = kids, lWidth = 0, cMinWidth = 0, cMaxWidth = 0, cnt = 0, valid = 0,
	 space = 0; i < kidCnt; ++i, ++kid )
    {
	XiC(*kid)->position.x = XiC(*kid)->position.y = 0;
	if( *kid == child )
	{
	    XiC(*kid)->position.width = child_size->width;
	    XiC(*kid)->position.height = child_size->height;
	}
	else
	{
	    XiC(*kid)->position.width = XiC(*kid)->request_width;
	    XiC(*kid)->position.height = XiC(*kid)->request_height;
	}

	if( !XiValidChild(*kid) ) continue;
	valid++;

	if( *kid == child )
	{
	    cbWidth = child_size->width + 2*child_size->border_width;
	}
	else
	{	
	    cbWidth = XiC(*kid)->request_width + 2*XtBorderWidth(*kid);
	}
	if( cMinWidth == 0 )
	{
	    cMinWidth = cbWidth;
	}
	else if( cbWidth < cMinWidth )
	{
	    cMinWidth = cbWidth;
	}
	if( cMaxWidth == 0 )
	{
	    cMaxWidth = cbWidth;
	}
	else if( cbWidth > cMaxWidth )
	{
	    cMaxWidth = cbWidth;
	}

	if( XiC(*kid)->stretchable ) ++cnt;

	if( !XiC(*kid)->show_label ) continue;

	space = XmColumn_label_spacing(cw);
	label = XiC(*kid)->label_widget;
	
	if( child == label )
	{
	    if( (int)child_size->width > lWidth )
	    {
		lWidth = child_size->width;
	    }
	}
	else
	{
	    if( (int)XiC(label)->request_width > lWidth )
	    {
		lWidth = XiC(label)->request_width;
	    }
	}
    }

    x = cw->manager.shadow_thickness + BBPart(cw)->margin_width;
    if( valid > 0 && (x + lWidth + space + cMaxWidth + x > col_width ) )
    {
	int have = (col_width - 2 * x),
	    want = lWidth + space + cMaxWidth,
	    diff = want - have;

	/* Try to subtract from the label space first; if we can't do it (it
	** may be 0 right now),
	** then the data fields will shrink until they are the size of the
	** smallest field, and after that the labels will shrink.
	** The shadow and margin aren't affected.
	*/
	if ( space - diff > 1)
		space -= diff;
	else
	{
		if (0 != space)
			space = 1;
	    	want = lWidth + space + cMinWidth;
	    	diff = want - have;

		if (diff > 0)
		{
			if( lWidth - diff > 1 )
			    lWidth -= diff;
			else
			    lWidth = 1;
		}
	}
    }

    /*
     * Calculating the widths for the various kids is a one shot, so lets
     * first walk through the kids and calculate all the width.
     */
    for( kid = kids, i = 0; i < kidCnt; ++i, ++kid )
    {
	if( !XiValidChild(*kid) ) continue;
	
	label = XiC(*kid)->label_widget;
	cBorder = XtBorderWidth(*kid);
	if (LayoutIsRtoLM(cw))
	    XiC(label)->position.x = col_width - x - lWidth;
	else
	    XiC(label)->position.x = x;
	XiC(label)->position.width = lWidth;

	/* cbWidth is whatever is left over */
	cbWidth = col_width - 
		((int)cw->manager.shadow_thickness +
		    (int)BBPart(cw)->margin_width +
			x + lWidth + space);
	if( cbWidth < 1 ) cbWidth = 1;
	cWidth = cbWidth - 2*cBorder;
	if( cWidth < 1 ) cWidth = 1;
	/* cWidth is now the value to use for XmFILL_FLUSH */
	if( XiFill(*kid) == XmFILL_RAGGED )
	{
	    if( child == *kid )
	    {
		if( (int) child_size->width < cWidth )
		{
		    cWidth = child_size->width;
		}
	    }
	    else
	    {
		if( (int) XiC(*kid)->request_width < cWidth )
		{
		    cWidth = XiC(*kid)->request_width;
		}
	    }
	}

	if (LayoutIsRtoLM(cw))
	    XiC(*kid)->position.x = col_width - (x + lWidth + space + cWidth);
	else
	    XiC(*kid)->position.x = x + lWidth + space;
	XiC(*kid)->position.width = cWidth;
    }

    /*
     * Now that we have calculated the x position and the width of
     * each of the children lets now try to calculate the y position
     * and the height.
     */

    space = XmColumn_item_spacing(cw);
    hExtra = col_height - height;
    /* but first make a quick check on reducing the itemSpacing */
    if (hExtra < 0) 
	{
	if (valid)
		{
		int totalItemSpacing = (valid - 1) * space;
		if (totalItemSpacing + hExtra > 0)
			space = (totalItemSpacing + hExtra)/(valid-1);
		else
			space = 1;
		}
	hExtra = 0;	/* or very close to it */
	}
    for( j = 0; j < 2; ++j )
    {
	do {
	    y = cw->manager.shadow_thickness +
		BBPart(cw)->margin_height;

	    if( j != 0 )
	    {
		cnt = valid;
	    }

	    if( cnt > 0 )
	    {
		hEach = hExtra / cnt;
		hLeft = hExtra % cnt;
	    }
	    else if( cnt == 0 )
	    {
		hEach = 0;
		hLeft = hExtra;
	    }
	    change = False;

	    for( kid = kids, i = 0; i < kidCnt; ++i, ++kid )
	    {
		if( !XiValidChild(*kid) ) continue;
		
		label = XiC(*kid)->label_widget;
		cHeight = XiC(*kid)->position.height;
		
		if( j == 0 || hExtra > 0 )
		{
		    stretch = XiC(*kid)->stretchable;
		}
		else
		{
		    stretch = True;
		}

		if( stretch )
		{
		    if( hExtra < 0 && cHeight > 1 )
		    {
			if( hEach != 0 )
			{
			    int tmp = -hEach;

			    change = True;
			    if( tmp < cHeight )
			    {
				hExtra += tmp;
				cHeight -= tmp;
			    }
			    else
			    {
				tmp = cHeight - 1;
				hExtra += tmp;
				cHeight = 1;
			    }
			}
			
			if( hLeft != 0 && cHeight > 1 )
			{
			    change = True;
			    hLeft++;
			    hExtra++;
			    cHeight--;
			}
		    }
		    else if( hExtra > 0 )
		    {
			change = True;
			cHeight += hEach;
			hExtra -= hEach;

			if( hLeft > 0 )
			{
			    cHeight++;
			    hLeft--;
			    hExtra--;
			}
		    }
		}

		if( cHeight < 1 ) cHeight = 1;
		if( child == *kid )
		{
		    cBorder = child_size->border_width;
		}
		else
		{
		    cBorder = XtBorderWidth(*kid);
		}

		if( XiC(*kid)->show_label )
		{
		    if( child == label )
		    {
			lHeight = child_size->height;
		    }
		    else
		    {
			lHeight = XiC(label)->request_height;
		    }
		}
		else
		{
		    lHeight = 1;
		}
		cbHeight = cHeight + 2 * cBorder;

		if( cbHeight > lHeight || stretch )
		{
		    lHeight = cbHeight;
		}
		else
		{
		    cHeight = lHeight - 2*cBorder;
		    if( cHeight < 1 ) cHeight = 1;
		    cbHeight = cHeight + 2*cBorder;
		}

		XiC(label)->position.y = y;
		XiC(label)->position.height = lHeight;

		XiC(*kid)->position.y = y;
		XiC(*kid)->position.height = cHeight;

		if( child == *kid )
		{
		    cBorder = child_size->border_width;
		}
		else
		{
		    cBorder = XtBorderWidth(*kid);
		}
		y += XiC(*kid)->position.height + (2 * cBorder) + space;
	    }
	} while( hExtra != 0 && change );
    }

    /*
     * If we get here and we still have some extra space we want to see
     * if the user wants to distribute the space between children or
     * not.
     */
    if( XmColumn_distribution(cw) == XmDISTRIBUTE_SPREAD &&
        hExtra > 0 )
    {
	if( valid == 1 )
	{
	    hEach = hExtra / 2;
	    XiC(*kids)->position.y += hEach;
	}
	else
	{
	    if( valid > 1 )
	    {
		valid--;
		hEach = hExtra / valid;
		hLeft = hExtra % valid;
	    }
	    else
	    {
		hEach = 0;
		hLeft = hExtra;
	    }

	    y = cw->manager.shadow_thickness +
		BBPart(cw)->margin_height;
	    for( i = 0, kid = kids; i < kidCnt; ++i, ++kid )
	    {
		if( !XiValidChild(*kid) ) continue;

		if( i > 0 )
		{
		    XiC(*kid)->position.y = y;
		    XiC(XiC(*kid)->label_widget)->position.y = y;
		}
		space = XmColumn_item_spacing(cw) + hEach;
		if( hLeft > 0 ) {
		    space++;
		    hLeft--;
		}
		if( child == *kid )
		{
		    cBorder = child_size->border_width;
		}
		else
		{
		    cBorder = XtBorderWidth(*kid);
		}
		y += XiC(*kid)->position.height + (2 * cBorder) +
		    space;
	    }
	}
    }

    if( child == NULL )
    {
	for( i = 0, kid = kids; i < kidCnt; ++i, ++kid )
	{
	    if( !XiValidChild(*kid) ) continue;

	    label = XiC(*kid)->label_widget;

	    if( XiC(*kid)->show_label )
	    {
		XtConfigureWidget(label, XiC(label)->position.x,
				  XiC(label)->position.y,
				  XiC(label)->position.width,
				  XiC(*kid)->position.height, 0);
	    }
	    
	    XtConfigureWidget(*kid,  XiC(*kid)->position.x,
			      XiC(*kid)->position.y,
			      XiC(*kid)->position.width,
			      XiC(*kid)->position.height,
			      XtBorderWidth(*kid));
	}
    }
}

/*
 * Function:
 *	VerifyConstraint(request, current, set)
 * Description:
 *	This function verifies the values for the Column child's constraint
 *	resources in "set" resetting them to the previous or default
 *	values if an invalid resource value was set.
 * Input:
 *	request	: Widget - the requested setting for the widget
 *	current : Widget - the current setting for the widget
 *	set     : Widget - the setting for the widget
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
VerifyConstraints(Widget request, Widget current, Widget set)
{
    Boolean  reset;

#if 0	/* POSITION HANDLING */
    reset = False;
    switch( XiC(set)->label_position )
    {
    case XiLABEL_POSITION_CENTER:
    case XiLABEL_POSITION_LEFT:
    case XiLABEL_POSITION_RIGHT:
    case XiLABEL_POSITION_TOP:
    case XiLABEL_POSITION_BOTTOM:
    case XiLABEL_POSITION_UNSPECIFIED:
	break;
    default:
	XmeWarning(set,
			"An illegal resource value was assigned to the resource XmNentryLabelPosition");
	reset = True;
	break;
    }
    if( reset )
    {
	XiC(set)->label_position = (current != NULL
				   ? XiC(current)->label_position
				   : XiLABEL_POSITION_UNSPECIFIED);
    }
#endif

    reset = False;
    switch( XiC(set)->label_alignment )
    {
    case XmALIGNMENT_BEGINNING:
    case XmALIGNMENT_CENTER:
    case XmALIGNMENT_END:
    case XmALIGNMENT_UNSPECIFIED:
	break;
    default:
	XmeWarning(set,
		"An illegal resource value was assigned to the resource XmNentryLabelAlignment");
	reset = True;
	break;
    }
    if( reset )
    {
	XiC(set)->label_alignment = (current != NULL
				    ? XiC(current)->label_alignment
				    : XmALIGNMENT_UNSPECIFIED);
    }

    reset = False;
    switch( XiC(set)->fill_style )
    {
    case XmFILL_UNSPECIFIED:
    case XmFILL_FLUSH:
    case XmFILL_RAGGED:
	break;
    default:
	XmeWarning(set,
		"An illegal resource value was assigned to the resource XmNfillStyle");
	reset = True;
	break;
    }
    if( reset )
    {
	XiC(set)->fill_style = (current != NULL
			       ? XiC(current)->fill_style
			       : XmFILL_UNSPECIFIED);
    }
}

/*
 * Function:
 *	CalcSize(cw, child, child_size, query, width, height)
 * Description:
 *	This function calculates and returns the prefered size for the
 *	column.
 * Input:
 *	cw         : XmColumnWidget    - the column widget
 *	child      : Widget            - a widget whose geometry is specified
 *	child_size : XtWidgetGeometry* - the specified child's geometry
 *	query      : Boolean           - query the kids?
 *	width      : Dimension*        - return the desired width
 *	height	   : Dimension*	       - return the desired height
 * Output:
 *	None.
 */
static void
CalcSize(XmColumnWidget cw, Widget child, XtWidgetGeometry *child_size,
	 Boolean query, Dimension *width, Dimension *height)
{
  int              _width = 0, _height = 0, cnt = 0;
  Cardinal         i, kidCnt = cw->composite.num_children;
  WidgetList       kid, kids = cw->composite.children;
  Widget           label;
  Dimension        cWidth, cHeight, cBorder, cSum = 0, lWidth, lHeight;
  Dimension        lSum = 0, space = 0, hSumSpace = 0;
  XtWidgetGeometry wants;

  for (i = 0, kid = kids; i < kidCnt; ++i, ++kid)
    {
      if (!XiValidChild(*kid)) continue;
      
      if (XiC(*kid)->show_label)
	{
	  space = XmColumn_label_spacing(cw);
	  hSumSpace += XmColumn_label_spacing(cw);
	}
      
      /* 
       * Check for the child widgets preferred geometry.
       * if the prefered geometry is greater than the requested
       * geometry, then set the query geometry to "True".
       * Doing this, column widget will take care of improper 
       * size settings on the compound children widgets (CR03821)
       */
      query = False;
      XtQueryGeometry(*kid, NULL, &wants);
      if (wants.width > XiC(*kid)->request_width || \
	  wants.height >  XiC(*kid)->request_height) 
	{
	  query = True;
	}
      
      if (*kid == child && child_size != NULL)
	{
	  cWidth = child_size->width;
	  cHeight = child_size->height;
	  cBorder = child_size->border_width;
	} else if (query) 
	  {
	    XtQueryGeometry(*kid, NULL, &wants);
	    
	    if (wants.request_mode & CWWidth)
	      {
		cWidth = wants.width;
		XiC(*kid)->request_width = wants.width;
	      }
	    else
	      {
		cWidth = XiC(*kid)->request_width;
	      }
	    
	    if (wants.request_mode & CWHeight)
	      {
		cHeight = wants.height;
		XiC(*kid)->request_height = wants.height;
	      }
	    else
	      {
		cHeight = XiC(*kid)->request_height;
	      }
	    
	    if (wants.request_mode & CWBorderWidth)
	      {
		cBorder = wants.border_width;
	      }
	    else
	      {
		cBorder = XtBorderWidth(*kid);
	      }
	  }
      else
	{
	  cWidth = XiC(*kid)->request_width;
	  cHeight = XiC(*kid)->request_height;
	  cBorder = XtBorderWidth(*kid);
	}
      
      cWidth += (2 * cBorder);
      cHeight += (2 * cBorder);
      if (XtIsManaged((label = XiC(*kid)->label_widget)))
	{
	  if (label == child && child_size != NULL)
	    {
	      lWidth = child_size->width;
	      lHeight = child_size->height;
	    }
	  else if (query)
	    {
	      XtQueryGeometry(label, NULL, &wants);
	      
	      if (wants.request_mode & CWWidth)
		{
		  lWidth = wants.width;
		}
	      else
		{
		  lWidth = XiC(label)->request_width;
		}
	      
	      if (wants.request_mode & CWHeight)
		{
		  lHeight = wants.height;
		}
	      else
		{
		  lHeight = XiC(label)->request_height;
		}
	    }
	  else
	    {
	      lWidth = XiC(label)->request_width;
	      lHeight = XiC(label)->request_height;
	    }
	}
      else
	{
	  lWidth = lHeight = 0;
	}
      
      if (XmColumn_orientation(cw) == XmVERTICAL)
	{
	  if (lWidth > lSum) lSum = lWidth;
	  if (cWidth > cSum) cSum = cWidth;
	  
	  _height += (lHeight > cHeight ? lHeight : cHeight);
	}
      else	/* XmHORIZONTAL Layout */
	{
	  /* Choose the maximum height */
	  if (_height < (int)cHeight) _height = cHeight;
	  if (_height < (int)lHeight) _height = lHeight;
	  
	  _width += lWidth + cWidth;
	}
      
      cnt++;
    }
  
  if (cnt > 1) --cnt;
  
  if (XmColumn_orientation(cw) == XmVERTICAL)
    {
      _width = lSum + cSum + space +
	2 * (cw->manager.shadow_thickness +
	     BBPart(cw)->margin_width);
      
      _height += (cnt * XmColumn_item_spacing(cw) +
		  2 * (cw->manager.shadow_thickness +
		       BBPart(cw)->margin_height));
    }
  else	/* XmHORIZONTAL Layout */
    {
      _width += (hSumSpace +
		 2 * (cw->manager.shadow_thickness +
		      BBPart(cw)->margin_width)) + cnt*XmColumn_item_spacing(cw);
      
      _height += 2 * (cw->manager.shadow_thickness +
		      BBPart(cw)->margin_height);
    }
  
  if (_width < 1) _width = 1;
  if (_height < 1) _height = 1;
  
  if (width != NULL) *width = _width;
  if (height != NULL) *height = _height;
}

/*
 * Function:
 *	CompareGeometry(geom1, geom2)
 * Description:
 *	This function compares to XtWidgetGeometry structure to see if
 *	the are equal.
 * Input:
 *	geom1 : XtWidgetGeometry* - a geometry spec
 *	geom2 : XtWidgetGeometry* - another geometry spec
 * Output:
 *	Boolean - True if the geometry structures are equal, else False
 */
static Boolean
CompareGeometry(XtWidgetGeometry *geom1, XtWidgetGeometry *geom2)
{
    Boolean result;

    result = (geom1 == NULL || geom2 == NULL) ||
	(geom1->request_mode != geom2->request_mode) ||
	(geom1->request_mode & CWX && geom1->x != geom2->x) ||
	(geom1->request_mode & CWY && geom1->y != geom2->y)  ||
	(geom1->request_mode & CWWidth && geom1->width != geom2->width) ||
	(geom1->request_mode & CWHeight && geom1->height != geom2->height) ||
	(geom1->request_mode & CWBorderWidth &&
	 geom1->border_width != geom2->border_width);

    return( !result );
}

/*
 * Function:
 *	CompareGeometryToWidget(geom, widget)
 * Description:
 *	Compares a geometry spec to a widget's actual geometry.
 * Input:
 *	geom   : XtWidgetGeometry* - the geometry
 *	widget : Widget            - the widget
 * Output:
 *	Boolean - True if the widget equals the geom spec, else False.
 */
static Boolean
CompareGeometryToWidget(XtWidgetGeometry *geom, Widget widget)
{
    Boolean result;

    result = (geom == NULL || widget == NULL) ||
	(geom->request_mode == 0) ||
	(geom->request_mode & CWX && geom->x != XtX(widget)) ||
        (geom->request_mode & CWY && geom->y != XtY(widget)) ||
        (geom->request_mode & CWWidth && geom->width != XtWidth(widget)) ||
        (geom->request_mode & CWHeight &&
	 geom->height != XtHeight(widget)) ||
        (geom->request_mode & CWBorderWidth &&
	 geom->border_width != XtBorderWidth(widget));

    return( !result );
}

/*
 * XmRCallProc routine for checking label_font_list before setting it to NULL
 * If constrainit's "check_set_render_table" is True, then function has 
 * been called twice on same widget, thus resource needs to be set NULL, 
 * otherwise leave it alone.
 */

/*ARGSUSED*/
static void 
CheckSetEntryLabelRenderTable(Widget wid, int offs, XrmValue *value)
{
  XmColumnConstraintPart* cc = XiC(wid);

  /* Check if been here before */
  if (cc->check_set_render_table)
      value->addr = NULL;
  else {
      cc->check_set_render_table = True;
      value->addr = (char*)&(cc->label_font_list);
  }

}

/*
 * XmRCallProc routine for checking label_font_list before setting it to NULL
 * If column's "check_set_render_table" is True, then function has 
 * been called twice on same widget, thus resource needs to be set NULL, 
 * otherwise leave it alone.
 */

/*ARGSUSED*/
static void 
CheckSetDefaultEntryLabelRenderTable(Widget wid, int offs, XrmValue *value)
{
  XmBulletinBoardPart* bb = BBPart(wid);
  XmColumnWidget c = (XmColumnWidget)wid;

  /* Check if been here before */
  if (c->column.check_set_render_table)
      value->addr = NULL;
  else {
      c->column.check_set_render_table = True;
      value->addr = (char*)&(bb->label_font_list);
  }

}
/*
 * Function:
 *	XmColumnLabelDestroyedCallback(widget, client, cbdata)
 * Description:
 *	This callback is called when a label that is associated with a field
 *	is destoyed.  The purpose of this callback is to inform the column
 *	when this happens to it does not try to do bad things.
 * Input:
 *	widget : Widget    - the widget being destroyed
 *	client : XtPointer - the widget that this label is associated with
 *	cbdata : XtPointer - unused.
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
XmColumnLabelDestroyedCallback(Widget widget, XtPointer client,
			       XtPointer cbdata)
{
    Widget field = (Widget) client;

    XiC(field)->label_widget = NULL;
}

/* ARGSUSED */
static void Get_entryLabelString (Widget widget, int offset, XtArgVal *value)
{
    (*value) = (XtArgVal) XmStringCopy(XiC(widget)->label_string);
}

/*
 * Function:
 *	XmCreateColumn(parent, name, arg_list, arg_cnt);
 * Description:
 *	Creates an unmanaged instance of an XmColumn and returns its
 *	widget id.
 * Input:
 *	parent   : Widget   - the parent of the new instance.
 *	name     : String   - the name of the new instance.
 *	arg_list : ArgList  - the arguments to create the instance with.
 *	arg_cnt  : Cardinal - the number of arguments in the list
 *	
 * Output:
 *	Widget - the widget id of the new instance.
 */
Widget
XmCreateColumn(Widget parent, String name, ArgList arg_list, Cardinal arg_cnt)
{
    return( XtCreateWidget(name, xmColumnWidgetClass, parent, arg_list,
			   arg_cnt) );
}

Widget 
XmVaCreateColumn(
        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, 
                         xmColumnWidgetClass,
                         parent, False, 
                         var, count);
    va_end(var);   
    return w;
}

Widget
XmVaCreateManagedColumn(
        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, 
                         xmColumnWidgetClass,
                         parent, True, 
                         var, count);
    va_end(var);   
    return w;
}
