/**
 *
 * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.0/Container.c,v 1.76 2002/04/17 19:35:59 dannybackx Exp $
 *
 * Copyright (C) 1997-1999 Free Software Foundation, Inc.
 * Copyright © 1999, 2000, 2001, 2002 LessTif Development Team
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/
#include <LTconfig.h>

#include <XmI/XmI.h>
#include <Xm/XmP.h>
#include <Xm/BaseClassP.h>
#include <Xm/Container.h>
#include <Xm/ContainerP.h>
#include <Xm/ContainerT.h>
#include <Xm/ContItemT.h>
#include <Xm/TransltnsP.h>
#include <Xm/PushBG.h>

#include <XmI/DebugUtil.h>

static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.0/Container.c,v 1.76 2002/04/17 19:35:59 dannybackx Exp $";

/*
 * Forward Declarations
 */

static void class_initialize(void);
static void class_part_initialize(WidgetClass widget_class);
static void Initialize(Widget, Widget, ArgList, Cardinal *);
static void resize(Widget w);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static void expose(Widget w, XEvent *event, Region region);
static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *, XtWidgetGeometry *);
static void _XmContainerLayout(Widget w, Dimension *pwid, Dimension *pht);
static void _XmContainerLayoutOL(Widget w, CwidNode n, Position x0, Position y0,
			Dimension *pwid, Dimension *pht, int lvl);
static void Destroy(Widget);

/* composite */
static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *, XtWidgetGeometry *);
static void ChangeManaged(Widget w);

/* constraint */
static void ConstraintInitialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args);
static void ConstraintDestroy(Widget w);
static Boolean ConstraintSetValues(Widget, Widget, Widget, ArgList, Cardinal *);

/*
 * Actions
 */
static void ContainerActivate(Widget, XEvent *, String *, Cardinal *);
static void ContainerBeginExtend(Widget, XEvent *, String *, Cardinal *);
static void ContainerBeginSelect(Widget, XEvent *, String *, Cardinal *);
static void ContainerBeginToggle(Widget, XEvent *, String *, Cardinal *);
static void ContainerButtonMotion(Widget, XEvent *, String *, Cardinal *);
static void ContainerCancel(Widget, XEvent *, String *, Cardinal *);
static void ContainerDeselectAll(Widget, XEvent *, String *, Cardinal *);
static void ContainerEndExtend(Widget, XEvent *, String *, Cardinal *);
static void ContainerEndSelect(Widget, XEvent *, String *, Cardinal *);
static void ContainerEndToggle(Widget, XEvent *, String *, Cardinal *);
static void ContainerEndTransfer(Widget, XEvent *, String *, Cardinal *);
static void ContainerExpandOrCollapse(Widget, XEvent *, String *, Cardinal *);
static void ContainerExtend(Widget, XEvent *, String *, Cardinal *);
static void ContainerExtendCursor(Widget, XEvent *, String *, Cardinal *);
static void ContainerHandleBtn1Down(Widget, XEvent *, String *, Cardinal *);
static void ContainerHandleBtn1Motion(Widget, XEvent *, String *, Cardinal *);
static void ContainerHandleBtn1Up(Widget, XEvent *, String *, Cardinal *);
static void ContainerHandleBtn2Down(Widget, XEvent *, String *, Cardinal *);
static void ContainerHandleBtn2Motion(Widget, XEvent *, String *, Cardinal *);
static void ContainerHandleBtn2Up(Widget, XEvent *, String *, Cardinal *);
static void ContainerMoveCursor(Widget, XEvent *, String *, Cardinal *);
static void ContainerPrimaryCopy(Widget, XEvent *, String *, Cardinal *);
static void ContainerPrimaryLink(Widget, XEvent *, String *, Cardinal *);
static void ContainerPrimaryMove(Widget, XEvent *, String *, Cardinal *);
static void ContainerSelect(Widget, XEvent *, String *, Cardinal *);
static void ContainerSelectAll(Widget, XEvent *, String *, Cardinal *);
static void ContainerStartTransfer(Widget, XEvent *, String *, Cardinal *);
static void ContainerToggleMode(Widget, XEvent *, String *, Cardinal *);

/*
 * Trait
 */
static void _ContainerTrait_GetValues(Widget container, XmContainerData d);

static XmContainerTraitRec _ContainerTraitRec = {
	/* version */		0,
	/* getvalues */		_ContainerTrait_GetValues
};

/*
 * Bitmaps, "stolen" from XltListTree
 */
#define folder_width 16
#define folder_height 12
static unsigned char folder_bits[] =
{
  0x00, 0x1f, 0x80, 0x20, 0x7c, 0x5f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
  0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0xfc, 0x3f,
};

#define folderopen_width 16
#define folderopen_height 12
static unsigned char folderopen_bits[] =
{
  0x00, 0x3e, 0x00, 0x41, 0xf8, 0xd5, 0xac, 0xaa, 0x54, 0xd5, 0xfe, 0xaf,
  0x01, 0xd0, 0x02, 0xa0, 0x02, 0xe0, 0x04, 0xc0, 0x04, 0xc0, 0xf8, 0x7f,
};

enum {
	_XmUnknown,
	_XmIconButton,
	_XmChild
};

/*
 * resources for the Container class
 */
#define Offset(field) XtOffsetOf(XmContainerRec, container.field)
static XtResource resources[] =
{
    {
	XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
	sizeof(Dimension), Offset(margin_h),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
	sizeof(Dimension), Offset(margin_w),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNautomaticSelection, XmCAutomaticSelection, XmRChar,
	sizeof(unsigned char), Offset(automatic),
	XmRImmediate, (XtPointer)XmAUTO_SELECT
    },
    {
	XmNcollapsedStatePixmap, XmCCollapsedStatePixmap, XmRPixmap,
	sizeof(Pixmap), Offset(collapsed_state_pixmap),
	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP	/* FIXME default should be dynamic */
    },
    {
	XmNconvertCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(convert_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdefaultActionCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(default_action_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdestinationCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(destination_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailColumnHeading, XmCDetailColumnHeading, XmRXmStringTable,
	sizeof(XmStringTable), Offset(detail_heading),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailColumnHeadingCount, XmCDetailColumnHeadingCount, XmRCardinal,
	sizeof(Cardinal), Offset(detail_heading_count),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailOrder, XmCDetailOrder, XmRCardinalList,
	sizeof(Cardinal *), Offset(detail_order),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailOrderCount, XmCDetailOrderCount, XmRCardinal,
	sizeof(Cardinal), Offset(detail_order_count),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNdetailTabList, XmCDetailTabList, XmRTabList,
	sizeof(XmTabList), Offset(detail_tablist),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNentryViewType, XmCEntryViewType, XmRChar,
	sizeof(unsigned char), Offset(entry_viewtype),
	XmRImmediate, (XtPointer)XmANY_ICON
    },
    {
	XmNexpandedStatePixmap, XmCExpandedStatePixmap, XmRPixmap,
	sizeof(Pixmap), Offset(expanded_state_pixmap),
	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP	/* FIXME should be dynamic */
    },
#if 0
    {
	XmNfontList, XmCFontList, XmRFontList,
	sizeof(XmFontList), Offset(fontlist),
	XmRImmediate, (XtPointer)0
    },
#endif
    {
	XmNlargeCellHeight, XmCCellHeight, XmRDimension,
	sizeof(Dimension), Offset(large_cell_height),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNlargeCellWidth, XmCCellWidth, XmRDimension,
	sizeof(Dimension), Offset(large_cell_width),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNlayoutType, XmCLayoutType, XmRChar,
	sizeof(unsigned char), Offset(layout_type),
	XmRImmediate, (XtPointer)XmSPATIAL
    },
    {
	XmNoutlineButtonPolicy, XmCOutlineButtonPolicy, XmRChar,
	sizeof(unsigned char), Offset(ob_policy),
	XmRImmediate, (XtPointer)XmOUTLINE_BUTTON_PRESENT
    },
    {
	XmNoutlineChangedCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(outline_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNoutlineColumnWidth, XmCOutlineColumnWidth, XmRDimension,
	sizeof(Dimension), Offset(ob_width),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNoutlineIndentation, XmCOutlineIndentation, XmRDimension,
	sizeof(Dimension), Offset(outline_indent),
	XmRImmediate, (XtPointer)40
    },
    {
	XmNoutlineLineStyle, XmCLineStyle, XmRChar,
	sizeof(unsigned char), Offset(outline_sep_style),
	XmRImmediate, (XtPointer)XmSINGLE
    },
    {
	XmNprimaryOwnership, XmCPrimaryOwnership, XmRChar,
	sizeof(unsigned char), Offset(primary_ownership),
	XmRImmediate, (XtPointer)XmOWN_POSSIBLE_MULTIPLE
    },
    {
	XmNrenderTable, XmCRenderTable, XmRRenderTable,
	sizeof(XmRenderTable), Offset(render_table),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNselectColor, XmCSelectColor, XmRPixel,
	sizeof(Pixel), Offset(select_color),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNselectedObjects, XmCSelectedObjects, XmRWidgetList,
	sizeof(WidgetList), Offset(selected_items),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNselectedObjectCount, XmCSelectedObjectCount, XmRInt,
	sizeof(unsigned int), Offset(selected_item_count),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNselectionCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(selection_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNselectionPolicy, XmCSelectionPolicy, XmRChar,
	sizeof(unsigned char), Offset(selection_policy),
	XmRImmediate, (XtPointer)XmEXTENDED_SELECT
    },
    {
	XmNselectionTechnique, XmCSelectionTechnique, XmRChar,
	sizeof(unsigned char), Offset(selection_technique),
	XmRImmediate, (XtPointer)XmTOUCH_OVER
    },
    {
	XmNsmallCellHeight, XmCCellHeight, XmRDimension,
	sizeof(Dimension), Offset(small_cell_height),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNsmallCellWidth, XmCCellWidth, XmRDimension,
	sizeof(Dimension), Offset(small_cell_width),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNspatialIncludeModel, XmCSpatialIncludeModel, XmRChar,
	sizeof(unsigned char), Offset(include_model),
	XmRImmediate, (XtPointer)XmAPPEND
    },
    {
	XmNspatialResizeModel, XmCSpatialResizeModel, XmRChar,
	sizeof(unsigned char), Offset(resize_model),
	XmRImmediate, (XtPointer)XmGROW_MINOR
    },
    {
	XmNspatialSnapModel, XmCSpatialSnapModel, XmRChar,
	sizeof(unsigned char), Offset(snap_model),
	XmRImmediate, (XtPointer)XmNONE
    },
    {
	XmNspatialStyle, XmCSpatialStyle, XmRChar,
	sizeof(unsigned char), Offset(spatial_style),
	XmRImmediate, (XtPointer)XmGRID
    },
#undef	Offset
};

#define	Offset(x) (XtOffsetOf(XmContainerConstraintRec, container.x))
static XtResource containerConstraintResources [] = {
	{
		XmNentryParent, XmCWidget, XmRWidget,
		sizeof(Widget), Offset(entry_parent),
		XmRImmediate, (XtPointer)0
	},
	{
		XmNoutlineState, XmCOutlineState, XmRUnsignedChar,
		sizeof(unsigned char), Offset(outline_state),
		XmRImmediate, XmCOLLAPSED
	},
	{
		XmNpositionIndex, XmCPositionIndex, XmRInt,
		sizeof(int), Offset(position_index),
		XmRImmediate, (XtPointer)0	/* FIX ME init in ConstraintInitialize ? */
	},
};
#undef Offset

static XtActionsRec actions[] = {
	{ "ContainerActivate",		ContainerActivate },
	{ "ContainerBeginExtend",	ContainerBeginExtend },
	{ "ContainerBeginSelect",	ContainerBeginSelect },
	{ "ContainerBeginToggle",	ContainerBeginToggle },
	{ "ContainerButtonMotion",	ContainerButtonMotion },
	{ "ContainerCancel",		ContainerCancel },
	{ "ContainerDeselectAll",	ContainerDeselectAll },
	{ "ContainerEndExtend",		ContainerEndExtend },
	{ "ContainerEndSelect",		ContainerEndSelect },
	{ "ContainerEndToggle",		ContainerEndToggle },
	{ "ContainerEndTransfer",	ContainerEndTransfer },
	{ "ContainerExpandOrCollapse",	ContainerExpandOrCollapse },
	{ "ContainerExtend",		ContainerExtend },
	{ "ContainerExtendCursor",	ContainerExtendCursor },
	{ "ContainerHandleBtn1Down",	ContainerHandleBtn1Down },
	{ "ContainerHandleBtn1Motion",	ContainerHandleBtn1Motion },
	{ "ContainerHandleBtn1Up",	ContainerHandleBtn1Up },
	{ "ContainerHandleBtn2Down",	ContainerHandleBtn2Down },
	{ "ContainerHandleBtn2Motion",	ContainerHandleBtn2Motion },
	{ "ContainerHandleBtn2Up",	ContainerHandleBtn2Up },
	{ "ContainerMoveCursor",	ContainerMoveCursor },
	{ "ContainerPrimaryCopy",	ContainerPrimaryCopy },
	{ "ContainerPrimaryLink",	ContainerPrimaryLink },
	{ "ContainerPrimaryMove",	ContainerPrimaryMove },
	{ "ContainerSelect",		ContainerSelect },
	{ "ContainerSelectAll",		ContainerSelectAll },
	{ "ContainerStartTransfer",	ContainerStartTransfer },
	{ "ContainerToggleMode",	ContainerToggleMode },
};

XmContainerClassRec xmContainerClassRec = {
    /* Core class part */
    {
	/* superclass            */ (WidgetClass) &xmManagerClassRec,
        /* class_name            */ "XmContainer",
	/* widget_size           */ sizeof(XmContainerRec),
	/* class_initialize      */ class_initialize,
	/* class_part_initialize */ class_part_initialize,
	/* class_inited          */ False,
	/* initialize            */ Initialize,
	/* initialize_hook       */ NULL,
	/* realize               */ XtInheritRealize,
	/* actions               */ actions,
	/* num_actions           */ XtNumber(actions),
	/* resources             */ resources,
	/* num_resources         */ XtNumber(resources),
	/* xrm_class             */ NULLQUARK,
	/* compress_motion       */ True,
	/* compress_exposure     */ XtExposeCompressMaximal,
	/* compress_enterleave   */ True,
	/* visible_interest      */ False,
	/* destroy               */ Destroy,
	/* resize                */ resize,
	/* expose                */ expose,
	/* set_values            */ SetValues,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ XtInheritSetValuesAlmost,
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ _XmContainer_defaultTranslations,
	/* query_geometry        */ QueryGeometry,
	/* display_accelerator   */ NULL,
	/* extension             */ (XtPointer)NULL /*&_XmContainerCoreClassExtRec*/
    },
    /* Composite class part */
    {
	/* geometry manager */ GeometryManager, 
        /* change_managed   */ ChangeManaged, 
        /* insert_child     */ XtInheritInsertChild,
        /* delete_child     */ XtInheritDeleteChild,
        /* extension        */ (XtPointer)NULL
    },
    /* Constraint class part */
    {
	/* subresources      */ containerConstraintResources,
        /* subresource_count */ XtNumber(containerConstraintResources), 
        /* constraint_size   */ sizeof(XmContainerConstraintRec),
        /* initialize        */ ConstraintInitialize,
        /* destroy           */ ConstraintDestroy,
        /* set_values        */ ConstraintSetValues,
        /* extension         */ NULL,  
    },
    /* XmManager class part */
    {
	/* translations                 */	XtInheritTranslations,
        /* syn_resources                */	NULL,
        /* num_syn_resources            */	0,
        /* syn_constraint_resources     */	NULL,
        /* num_syn_constraint_resources */	0,
        /* parent_process               */	XmInheritParentProcess,
	/* extension                    */	(XtPointer)NULL
    },
    /* XmContainer Area part */
    {
	/* extension */				NULL,
    },
};

WidgetClass xmContainerWidgetClass = (WidgetClass)&xmContainerClassRec;

Widget XmCreateContainer(Widget parent, String name, ArgList arglist, Cardinal argcount)
{
	return XtCreateWidget(name, xmContainerWidgetClass, parent, arglist, argcount);
}

static void class_part_initialize(WidgetClass widget_class)
{
	/* FIX ME: Needs to be implemented */
	DEBUGOUT(_LtDebug(__FILE__, NULL, "XmContainer class_part_initialize\n"));
}

static XtTranslations container_traversal_trans;

static void class_initialize(void)
{
	container_traversal_trans = XtParseTranslationTable(_XmContainer_traversalTranslations);

	if (! XmeTraitSet((XtPointer)xmContainerWidgetClass, XmQTcontainer,
			(XtPointer) &_ContainerTraitRec)) {
		_XmWarning(NULL, "XmContainer ClassInitialize: XmeTraitSet failed\n");
	}
}

static void Initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	Dimension	wid, ht;
	XGCValues	values;
	XtGCMask	mask;

	/* FIX ME: Needs to be implemented */

	DEBUGOUT(_LtDebug(__FILE__, new_w, "XmContainer initialize\n"));

	XtAugmentTranslations(new_w, container_traversal_trans);

	ContainerFirstNode(new_w) = 0;
	ContainerLastNode(new_w) = 0;
	ContainerIconHeader(new_w) = 0;
	ContainerMarqueeMode(new_w) = False;
	ContainerSelectedItemCount(new_w) = 0;
	ContainerSelectedItems(new_w) = NULL;
	ContainerAnchorCWid(new_w) = NULL;
	ContainerDruggee(new_w) = NULL;
	ContainerSizeOb(new_w) = NULL;
	ContainerDragContext(new_w) = NULL;
	ContainerDetailOrder(new_w) = NULL;
	ContainerDetailOrderCount(new_w) = 0;
	ContainerDetailHeading(new_w) = NULL;
	ContainerOutlineSegs(new_w) = NULL;
	ContainerDragOffsetX(new_w) = 0;
	ContainerDragOffsetY(new_w) = 0;
	ContainerSavedDetailHeadingCount(new_w) = 0;

	ContainerSmallCellDimFixed(new_w) = False;
	ContainerLargeCellDimFixed(new_w) = False;

	_XmContainerLayout(new_w, &wid, &ht);

	XtWidth(new_w) = (wid < 100) ? 100 : wid;
	XtHeight(new_w) = (ht < 100) ? 100 : ht;

	if (ContainerCollapsedStatePixmap(new_w) == XmUNSPECIFIED_PIXMAP) {
		ContainerCollapsedStatePixmap(new_w) = XCreateBitmapFromData(
			XtDisplay(new_w), RootWindowOfScreen(XtScreen(new_w)),
			(char *)folder_bits, folder_width, folder_height);
	}
	if (ContainerExpandedStatePixmap(new_w) == XmUNSPECIFIED_PIXMAP) {
		ContainerExpandedStatePixmap(new_w) = XCreateBitmapFromData(
			XtDisplay(new_w), RootWindowOfScreen(XtScreen(new_w)),
			(char *)folderopen_bits, folderopen_width, folderopen_height);
	}

	ContainerMarqueeGC(new_w) = NULL;	/* FIX ME */
	mask = GCForeground;
	values.foreground = MGR_Foreground(new_w);
	ContainerNormalGC(new_w) = XtGetGC(new_w, mask, &values);

	/*
	 * XmNselectColor
	 *	Specifies a Pixel that can be accessed by children of the Container
	 *	and used to indicate that the child is in a selected state.
	 *	In addition to a Pixel value, the following symbolic values can be
	 *	specified:
	 *		XmDEFAULT_SELECT_COLOR
	 *			Specifies a color between the background and the bottom
	 *			shadow color. 
	 *		XmREVERSED_GROUND_COLORS
	 *			Forces the select color to the foreground color and
	 *			causes the default color of any text rendered over the
	 *			select color to be the background color.
	 *		HIGHLIGHT_COLOR
	 *			Forces the fill color to use the highlight color.
	 */
	switch (ContainerSelectColor(new_w)) {
	case XmDEFAULT_SELECT_COLOR:
		break;
	case XmREVERSED_GROUND_COLORS:
		break;
	case XmHIGHLIGHT_COLOR:
		break;
	default:
		/* Don't change it */
		break;
	}
}

static void resize(Widget w)
{
	DEBUGOUT(_LtDebug(__FILE__, w, "XmContainer resize (%d x %d)\n",
		XtWidth(w), XtHeight(w)));
	_XmContainerLayout(w, NULL, NULL);
}

static Boolean
SetValues(Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	/* FIX ME: Needs to be implemented */
#define	NE(r)	(r(request) != r(new_w))

	DEBUGOUT(_LtDebug(__FILE__, new_w, "XmContainer SetValues\n"));
	DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));

	if (NE(ContainerEntryViewType)) {
		/* Must pass this to children using the ContainerItem trait */

		XmContainerItemTrait	tr;
		int			i;
		Widget			child;
		XmContainerItemDataRec	data;

		data.valueMask = ContItemViewType;
		data.view_type = ContainerEntryViewType(new_w);

		for (i=0; i<MGR_NumChildren(new_w); i++) {
			child = MGR_Children(new_w)[i];
			if ((tr = (XmContainerItemTrait)XmeTraitGet((XtPointer)XtClass(child),
								XmQTcontainerItem))) {
				tr->setValues(child, &data);
			} else {
				continue;	/* Shouldn't happen */
			}
		}
	}

	return True;
#undef	NE
}

static void expose(Widget w, XEvent *event, Region region)
{
	if (! XtIsRealized(w))
		return;

	DEBUGOUT(_LtDebug(__FILE__, w, "XmContainer expose\n"));
	/* FIX ME: Needs to be implemented */

	_XmRedisplayGadgets(w, event, region);

	if (ContainerLayoutType(w) == XmOUTLINE) { /* Draw the lines */
		int	i;

		for (i=0; i<MGR_NumChildren(w); i++) {
			Widget 		c, last, child = MGR_Children(w)[i];
			CwidNode	cn, n;
			Position	x0, y0, my;

			if (child->core.being_destroyed)
				continue;
			if (CC_OutlineState(child) == XmCOLLAPSED)
				continue;
			if ((cn = CC_Child(child)) == NULL)
				continue;

			/* Find the non-icon child with the highest Y */
			my=-1; last = NULL;
			for (n=cn; n; n=n->next_ptr) {
				c = n->widget_ptr;

				if (CC_CWidType(c) == _XmIconButton)
					continue;
				else if (XtY(c) > my) {
					my = XtY(c);
					last = c;
				}
			}
			if (! last)
				last = cn->widget_ptr;

			/* From the related widget - this is the button */
			c = CC_Related(child);
			x0 = XtX(c) + XtWidth(c) / 2;
			y0 = XtY(c) + XtHeight(c);

			my = XtY(last) + XtHeight(last) / 2;

			/* Vertical line */
			XDrawLine(XtDisplay(w), XtWindow(w),
				ContainerNormalGC(w),
				x0, y0, x0, my);
			/*
			 * Horizontal lines
			 * Draw these only to the folder button if a child has children of its own.
			 */
			for (n=cn; n; n=n->next_ptr) {
				Position	x, y;

				c = n->widget_ptr;

				if (CC_CWidType(c) == _XmIconButton)
					continue;

				y = XtY(c) + XtHeight(c) / 2;

				if (n->child_ptr && CC_Related(c)) {
					Widget	r = CC_Related(c);
					x = XtX(r);
				} else {
					x = XtX(c);
				}

				XDrawLine(XtDisplay(w), XtWindow(w), ContainerNormalGC(w),
					x0, y, x, y);
			}
			
		}
	}
}

/*
 * Utilities to handle the selection list.
 */
static void ClearSelectedItems(Widget w)
{
	XmContainerItemTrait	t;
	int			i;
	XmContainerItemDataRec	r;

	for (i=0; i<ContainerSelectedItemCount(w); i++) {
		Widget child = ContainerSelectedItems(w)[i];

		/* Call the trait to change the appearance */
		t = (XmContainerItemTrait) XmeTraitGet((XtPointer)XtClass(child),
			XmQTcontainerItem);
		if (t) {
			r.valueMask = ContItemVisualEmphasis;
			r.visual_emphasis = XmNOT_SELECTED;
			t->setValues(child, &r);
		}
	}

	if (ContainerSelectedItems(w))
		XtFree((char *)ContainerSelectedItems(w));
	ContainerSelectedItems(w) = NULL;
	ContainerSelectedItemCount(w) = 0;
}

static void AddSelectedItem(Widget w, Widget si)
{
	int			i;
	XmContainerItemTrait	t;

	if (! si)
		return;

	for (i=0; i<ContainerSelectedItemCount(w); i++)
		if (ContainerSelectedItems(w)[i] == si)
			return;

	if (ContainerSelectedItems(w)) {
		ContainerSelectedItems(w) = (WidgetList)XtRealloc(
			(char *)ContainerSelectedItems(w),
			(ContainerSelectedItemCount(w)+2) * sizeof(Widget));
	} else {
		ContainerSelectedItems(w) = (WidgetList)XtMalloc(2 * sizeof(Widget));
	}
	ContainerSelectedItems(w)[ContainerSelectedItemCount(w)] = si;
	ContainerSelectedItemCount(w)++;
	ContainerSelectedItems(w)[ContainerSelectedItemCount(w)] = NULL;

	/* Call the trait to change the appearance */
	t = (XmContainerItemTrait) XmeTraitGet((XtPointer)XtClass(si),
		XmQTcontainerItem);
	if (t) {
		XmContainerItemDataRec	r;

		r.valueMask = ContItemVisualEmphasis;
		r.visual_emphasis = XmSELECTED;
		t->setValues(si, &r);
	}
}

static Boolean ItemIsSelected(Widget w, Widget child)
{
	int	i;

	for (i=0; i<ContainerSelectedItemCount(w); i++)
		if (ContainerSelectedItems(w)[i] == child)
			return True;
	return False;
}

static void RemoveSelectedItem(Widget w, Widget child)
{
	int	i, j;
	XmContainerItemTrait	t;

	for (j=-1, i=0; i<ContainerSelectedItemCount(w); i++)
		if (ContainerSelectedItems(w)[i] == child)
			j = i;
	if (j < 0)
		return;	/* FIX ME error message ? */
	for (i=j; i<ContainerSelectedItemCount(w)-1; i++)
		ContainerSelectedItems(w)[i] = ContainerSelectedItems(w)[i+1];
	if (ContainerSelectedItemCount(w) > 0)
		ContainerSelectedItemCount(w)--;
	
	/* Don't bother making the structure smaller */
	/* Call the trait to change the appearance */
	t = (XmContainerItemTrait) XmeTraitGet((XtPointer)XtClass(child),
		XmQTcontainerItem);
	if (t) {
		XmContainerItemDataRec	r;

		r.valueMask = ContItemVisualEmphasis;
		r.visual_emphasis = XmNOT_SELECTED;
		t->setValues(child, &r);
	}
	
}

static void MarqueeStart(Widget w, XEvent *evp)
{
	/* FIX ME need to check evp->type first */
	ContainerMarqueeStart(w).x = evp->xmotion.x;
	ContainerMarqueeStart(w).y = evp->xmotion.y;
}

static void SelectItemRange(Widget w, Widget a, Widget b)
{
	/* FIX ME how do you determine the range ?
	 * Assuming it is in child order,  but this is almost certainly wrong.
	 */
	int	i, ia=0, ib=0;
	for (i=0; i<MGR_NumChildren(w); i++) {
		if (MGR_Children(w)[i] == a)
			ia = i;
		if (MGR_Children(w)[i] == b)
			ib = i;
	}

	if (ia > ib) {
		i = ia;
		ia = ib;
		ib = i;
	}
	for (i=ia; i<=ib; i++) {
			AddSelectedItem(w, MGR_Children(w)[i]);
	}
}

static void UnselectItemRange(Widget w, Widget a, Widget b)
{
	/* FIX ME how do you determine the range ?
	 * Assuming it is in child order,  but this is almost certainly wrong.
	 */
	int	i, ia=0, ib=0;
	for (i=0; i<MGR_NumChildren(w); i++) {
		if (MGR_Children(w)[i] == a)
			ia = i;
		if (MGR_Children(w)[i] == b)
			ib = i;
	}
	if (ia > ib) {
		i = ia;
		ia = ib;
		ib = i;
	}
	for (i=ia; i<=ib; i++) {
		RemoveSelectedItem(w, MGR_Children(w)[i]);
	}
}

/*
 * For debugging purposes
 */
static void ContainerDebugPrintTree(int lvl, Widget cont, CwidNode node)
{
	int	i;

	if (lvl == 0) {
		for (node = ContainerFirstNode(cont); node; node = node->next_ptr) {
			ContainerDebugPrintTree(lvl+1, cont, node);
		}
		return;
	}
	if (node == 0)
		return;

	for (i=0; i<lvl; i++)
		DEBUGOUT(_LtDebug0(__FILE__, cont, "    "));
	DEBUGOUT(_LtDebug0(__FILE__, cont, "%s\n", XtName(node->widget_ptr)));
	for (node = node->child_ptr; node; node = node->next_ptr)
		ContainerDebugPrintTree(lvl+1, cont, node);
}

/*
 * Recursive function to walk down the tree
 */
static void
_XmContainerLayoutOL(Widget w, CwidNode n, Position x0, Position y0,
			Dimension *pwid, Dimension *pht, int lvl)
{
	Position	oldx = x0,
			mx, my, x, y;
	CwidNode	node;

/* FIX ME */
#define	HMARGIN	8
#define	WMARGIN	4

	if (n == NULL)
		return;

	ContainerDebugPrintTree(0, w, NULL);

	/*
	 * If we have a lvl parameter then we might as well use it to
	 * prevent us from having infinite recursion.
	 */
	if (lvl > MGR_NumChildren(w) + 5) {
		_XmWarning(w, "Recursion problem !!\n");
		return;
	}

	mx = x0;
	my = y0;
	node = n;
	while (node) {
		Widget	nw = node->widget_ptr;

		x0 = oldx;

		DEBUGOUT(_LtDebug2(__FILE__, w, nw,
			"_XmContainerLayoutOL[%d](X0 %d Y0 %d)(next %s, child %s)\n",
			lvl, x0, y0,
			node->next_ptr ? XtName(node->next_ptr->widget_ptr)
					: "none",
			node->child_ptr ? XtName(node->child_ptr->widget_ptr)
					: "none"));

		if (CC_CWidType(nw) == _XmIconButton) {
			node = node->next_ptr;
			continue;
		}

		/* Position the widget and, if relevant, its icon */
		if (node->child_ptr && CC_Related(nw)) {
			Widget other = CC_Related(nw);
			Position	ox, oy;

			ox = x0;
			oy = y0 + HMARGIN + (XtHeight(nw) - XtHeight(other)) / 2;
			x = x0 + WMARGIN + ContainerMarginWidth(w) + XtWidth(other);
			y = y0 + HMARGIN;

			if (ox != XtX(other) || oy != XtY(other)) {
				_XmMoveObject(other, ox, oy);
				DEBUGOUT(_LtDebug2(__FILE__, w, other,
					"Move related child to %d %d\n", ox, oy));
			}
			if (x != XtX(nw) || y != XtY(nw)) {
				_XmMoveObject(nw, x, y);
			}
			mx = x + XtWidth(nw) + XtWidth(other)
				+ 2 * ContainerMarginWidth(w) + 2 * WMARGIN;
			my = y + ContainerMarginHeight(w) + XtHeight(nw) + HMARGIN;
		} else {
			x = x0;
			y = y0 + HMARGIN;
			if (x != XtX(nw) || y != XtY(nw)) {
				_XmMoveObject(nw, x, y);
			}
			
			mx = x + ContainerMarginWidth(w) + WMARGIN + XtWidth(nw);
			my = y + ContainerMarginHeight(w) + HMARGIN + XtHeight(nw);
		}
		DEBUGOUT(_LtDebug2(__FILE__, w, nw,
			"Move child to %d %d\n", x, y));

		if (node->child_ptr) {
			if (CC_OutlineState(nw) == XmEXPANDED) {
				_XmContainerLayoutOL(w, node->child_ptr,
					x + ContainerOutlineIndent(w), my,
					(Dimension *)&x0, (Dimension *)&y0, lvl+1);
				if (x0 > mx)
					mx = x0;
				if (my < y0)
					my = y0;
			} else { /* XmCOLLAPSED */
				/* FIX ME  x0 = mx; */ y0 = my;
			}
		}
		node = node->next_ptr;

		/* X0 is updated at the beginning of the loop. */
		y0 = my;
	}
	x0 = mx;
	if (*pwid < mx)
		*pwid = mx;
	y0 = my;
	if (*pht < my)
		*pht = my;
	DEBUGOUT(_LtDebug(__FILE__, w, "_XmContainerLayoutOL[%d] -> %d %d\n",
		lvl, x0, y0));
}

/*
 * "Outline" Layout
 *
 * Show items in a tree, in PositionIndex order within EntryParent order.
 * Lines are drawn to show parent-child relationship.
 */
static void _XmContainerLayoutOutline(Widget w, Dimension *pwid, Dimension *pht)
{
	Dimension wid, ht;
	int		i;

	wid = ContainerMarginWidth(w);
	ht = 0;

	DEBUGOUT(_LtDebug(__FILE__, w, "_XmContainerLayoutOutline(%d children)\n",
		MGR_NumChildren(w)));

	_XmContainerLayoutOL(w, ContainerFirstNode(w),
		ContainerMarginWidth(w), ContainerMarginHeight(w),
		&wid, &ht, 0);

	/* Determine widget size */
	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget child = MGR_Children(w)[i];
		if (XtIsRealized(child) && XtIsManaged(child)) {
			Dimension	m;
			m = XtX(child) + XtWidth(child) + ContainerMarginWidth(w);
			if (m > wid)
				wid = m;
			m = XtY(child) + XtHeight(child) + ContainerMarginHeight(w);
			if (ht < m)
				ht = m;
		}
	}

	if (pwid)
		*pwid = wid;
	if (pht)
		*pht = ht;
	return;
}

/*
 * FIX ME this is simplistic
 *
 * ContainerLayoutType == XmSPATIAL
 *
 * Layout influenced by
 *	ContainerSpatialStyle (XmCELLS, XmGRID, XmNONE)
 *	ContainerSpatialIncludeModel (XmAPPEND, XmCLOSEST, XmFIRST_FIT)
 *	ContainerSpatialSnapModel (XmCENTER, XmSNAP_TO_GRID, XmNONE)
 *
 * Items with XmNentryParent values are not displayed.
 *
 * XmNspatialStyle
 * XmCELLS	Lays out items within a grid of same-size cells. Each item
 *		occupies as many cells as required to contain the item
 *		dimensions.
 * XmGRID	Lays out items within a grid of same-size cells. Each item
 *		occupies only one cell. Items that are larger than the cell
 *		size may overlap other items.
 * XmNONE	Lays out items according to XmNx and XmNy.
 *
 * XmNspatialSnapModel
 * XmCENTER		Center the items as follows, depending on the value of
 *			XmNentryViewType:
 *	XmLARGE_ICON		The child is centered in the cell horizontally
 *				and baseline-aligned vertically.
 *	XmSMALL_ICON		The child is centered in the cell vertically on its
 *				baseline and aligned with the left or right of the
 *				cell horizontally, depending on the value of
 *				XmNlayoutDirection.
 * XmSNAP_TO_GRID	Position the item at the upper-left or upper-right corner
 *			of the cell(s), depending on the value of
 *			XmNlayoutDirection.
 * XmNONE		Position the item according to the position specified
 *			by XmNx and XmNy. If the position is not within the
 *			coordinates of the cell(s), then position the item at
 *			the upper-left or upper-right corner of the cell(s),
 *			depending on the value of XmNlayoutDirection.
 *
 * XmNspatialIncludeModel
 *	Specifies the layout of an item when the item is managed in the Container
 *	when XmNlayoutType is XmSPATIAL and XmNspatialStyle is XmGRID or XmCELLS.
 * XmAPPEND 	Places the item after the last occupied cell according to
 *		XmNlayoutDirection.
 * XmCLOSEST	Places the item in the free cell closest to the position
 *		specified by XmNx and XmNy.
 * XmFIRST_FIT	Places the item in the first free cell according to
 *		XmNlayoutDirection.
 *
 * XmNspatialResizeModel
 *	Specifies how Container will attempt to grow its dimensions when
 *	XmNlayoutType is XmSPATIAL and XmNspatialStyle is XmGRID or XmCELLS
 *	and there are not enough cells to contain a new Container item.
 * XmGROW_BALANCED	Container will request both width and height growth
 *			from its parent.
 * XmGROW_MAJOR		Container will request growth in its major dimension
 *			from its parent. Container's major dimension is width
 *			when the precedence of XmNlayoutDirection is horizontal,
 *			and height when vertical.
 * XmGROW_MINOR		Container will request growth in its minor dimension from
 *			its parent. Container's minor dimension is height when
 *			the precedence of XmNlayoutDirection is horizontal, and
 *			width when vertical. 
 */
static void _XmContainerLayoutSpatial(Widget w, Dimension *pwid, Dimension *pht)
{
	Dimension	cw=0, ch=0, contwid, contht, incx, incy, rowmaxht=0;
	Cardinal	i;
	Position	x, y;
	int		nrows, ncells, ncols, rowindex;

	DEBUGOUT(_LtDebug(__FILE__, w,
		"XmContainerLayoutSpatial: children %d Init dim %dx%d "
		"SpatialStyle %s IncludeModel %s "
		" SnapModel %s ResizeModel %s\n",
		MGR_NumChildren(w),
		XtWidth(w), XtHeight(w),
		(ContainerSpatialStyle(w) == XmCELLS) ? "XmCELLS" :
		(ContainerSpatialStyle(w) == XmGRID) ? "XmGRID" :
		(ContainerSpatialStyle(w) == XmNONE) ? "XmNONE" :
		"???",
		(ContainerIncludeModel(w) == XmAPPEND) ? "XmAPPEND" :
		(ContainerIncludeModel(w) == XmCLOSEST) ? "XmCLOSEST" :
		(ContainerIncludeModel(w) == XmFIRST_FIT) ? "XmFIRST_FIT" :
		"???",
		(ContainerSnapModel(w) == XmCENTER) ? "XmCENTER" :
		(ContainerSnapModel(w) == XmSNAP_TO_GRID) ? "XmSNAP_TO_GRID" :
		(ContainerSnapModel(w) == XmNONE) ? "XmNONE" :
		"???",
		(ContainerSpatialResizeModel(w) == XmGROW_BALANCED) ? "XmGROW_BALANCED" :
		(ContainerSpatialResizeModel(w) == XmGROW_MAJOR) ? "XmGROW_MAJOR" :
		(ContainerSpatialResizeModel(w) == XmGROW_MINOR) ? "XmGROW_MINOR" :
		"???"));

	/* Figure out cell size */
	if (ContainerSpatialStyle(w) == XmCELLS || ContainerSpatialStyle(w) == XmGRID) {
		if (ContainerSmallCellDimFixed(w) == False
				&& ContainerEntryViewType(w) == XmSMALL_ICON) {
			/* Initialize */
			if (MGR_NumChildren(w)) {
				ContainerSmallCellWidth(w) = XtWidth(MGR_Children(w)[0]);
				ContainerSmallCellHeight(w) = XtHeight(MGR_Children(w)[0]);
			} else {
				ContainerSmallCellWidth(w) =
				ContainerSmallCellHeight(w) = 1;
			}
			for (i=0; i<MGR_NumChildren(w); i++) {
				Widget	child = MGR_Children(w)[i];
				if (! XtIsManaged(child))
					continue;
				if (CC_EntryParent(child))
					continue;
				if (ContainerSpatialStyle(w) == XmCELLS) {
					if (ContainerSmallCellHeight(w) > XtHeight(child))
						ContainerSmallCellHeight(w) = XtHeight(child);
					if (ContainerSmallCellWidth(w) > XtWidth(child))
						ContainerSmallCellWidth(w) = XtWidth(child);
				} else {
					if (ContainerSmallCellHeight(w) < XtHeight(child))
						ContainerSmallCellHeight(w) = XtHeight(child);
					if (ContainerSmallCellWidth(w) < XtWidth(child))
						ContainerSmallCellWidth(w) = XtWidth(child);
				}
			}
			cw = ContainerSmallCellWidth(w);
			ch = ContainerSmallCellHeight(w);
		} else if (ContainerLargeCellDimFixed(w) == False
				&& ContainerEntryViewType(w) == XmLARGE_ICON) {
			/* Initialize */
			if (MGR_NumChildren(w)) {
				ContainerLargeCellWidth(w) = XtWidth(MGR_Children(w)[0]);
				ContainerLargeCellHeight(w) = XtHeight(MGR_Children(w)[0]);
			} else {
				ContainerLargeCellWidth(w) =
				ContainerLargeCellHeight(w) = 1;
			}
			for (i=0; i<MGR_NumChildren(w); i++) {
				Widget	child = MGR_Children(w)[i];

				if (child->core.being_destroyed)
					continue;
				if (! XtIsManaged(child))
					continue;
				if (CC_EntryParent(child))
					continue;
				if (ContainerSpatialStyle(w) == XmCELLS) {
					if (ContainerLargeCellHeight(w) > XtHeight(child))
						ContainerLargeCellHeight(w) = XtHeight(child);
					if (ContainerLargeCellWidth(w) > XtWidth(child))
						ContainerLargeCellWidth(w) = XtWidth(child);
				} else {
					if (ContainerLargeCellHeight(w) < XtHeight(child))
						ContainerLargeCellHeight(w) = XtHeight(child);
					if (ContainerLargeCellWidth(w) < XtWidth(child))
						ContainerLargeCellWidth(w) = XtWidth(child);
				}
			}
			cw = ContainerLargeCellWidth(w);
			ch = ContainerLargeCellHeight(w);
		} else {
			if (ContainerEntryViewType(w) == XmLARGE_ICON) {
				cw = ContainerLargeCellWidth(w);
				ch = ContainerLargeCellHeight(w);
			} else if (ContainerEntryViewType(w) == XmSMALL_ICON) {
				cw = ContainerSmallCellWidth(w);
				ch = ContainerSmallCellHeight(w);
			}
		}
	}

	DEBUGOUT(_LtDebug(__FILE__, w, "XmContainerLayoutSpatial: cell size %d %d\n", cw, ch));
	/*
	 * Figure out how many cells we need
	 */
	for (ncells=0, i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];

		if (child->core.being_destroyed)
			continue;
		if (! XtIsManaged(child))
			continue;
		if (CC_EntryParent(child))
			continue;
		switch (ContainerSpatialStyle(w)) {
		case XmGRID:
			ncells++;
			break;
		case XmCELLS:
			ncells++;
			ncells += XtWidth(child) / cw;
			ncells += XtHeight(child) / ch;
			break;
		default:
			break;
		} /* switch() */
	}

	/*
	 * Do we need to grow, and if yes, in which direction ?
	 */
	switch (ContainerSpatialResizeModel(w)) {
	case XmGROW_BALANCED:
		/* FIX ME, fall through for now */
	default:
	case XmGROW_MAJOR:
		if (MGR_LayoutDirection(w) == XmHORIZONTAL) {
			/* Increment width */
			contht = XtHeight(w) - 2 * ContainerMarginHeight(w);
			nrows = contht / ch;
			if (nrows) {
				ncols = ncells / nrows;
				if ((ncells % nrows) != 0)
					ncols++;
			} else
				ncols = ncells;
			contwid = cw * ncols;
		} else {
			/* Increment height */
			contwid = XtWidth(w) - 2 * ContainerMarginWidth(w);
			ncols = contwid / cw;
			if (ncols) {
				nrows = ncells / ncols;
				if ((ncells % ncols) != 0)
					nrows++;
			} else
				nrows = ncells;
			contht = ch * nrows;
		}
		break;
	case XmGROW_MINOR:
		if (MGR_LayoutDirection(w) == XmVERTICAL) {
			/* Increment width */
			contht = XtHeight(w) - 2 * ContainerMarginHeight(w);
			if (ch)
				nrows = contht / ch;
			else
				nrows = 1;
			if (nrows) {
				ncols = ncells / nrows;
				if ((ncells % nrows) != 0)
					ncols++;
			} else
				ncols = ncells;
			contwid = cw * ncols;
		} else {
			/* Increment height */
			contwid = XtWidth(w) - 2 * ContainerMarginWidth(w);
			if (cw)
				ncols = contwid / cw;
			else
				ncols = 1;
			if (ncols) {
				nrows = ncells / ncols;
				if ((ncells % ncols) != 0)
					nrows++;
			} else
				nrows = ncells;
			contht = ch * nrows;
		}
	}

	/*
	 * Layout children over cells and figure out how big Container must be.
	 */
	x = ContainerMarginWidth(w);
	y = ContainerMarginHeight(w);
	rowindex = 1;
	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];

		if (! XtIsManaged(child))
			continue;
		if (child->core.being_destroyed)
			continue;

		if (CC_EntryParent(child)) {
			/*
			 * Move out of sight. Can't unmanage because we wouldn't know
			 * when/whether to manage again.
			 */
			_XmMoveObject(child,
				-100-XtWidth(child),
				-100-XtHeight(child));
			continue;
		}

		if (ContainerSpatialStyle(w) == XmNONE) {
			x = CC_UserX(child);
			y = CC_UserY(child);
		}

		_XmMoveObject(child, x, y);

		switch (ContainerSpatialStyle(w)) {
		case XmCELLS:
			_XmMoveObject(child, x, y);

			incx = XtWidth(child) / cw;
			incx *= cw;
			incy = XtHeight(child) / ch;
			incy *= ch;
			if (rowmaxht < incy)
				rowmaxht = incy;
			if (x + incx >= contwid) {
				x = ContainerMarginWidth(w);
				y += rowmaxht;
				rowmaxht = 0;
			}
			break;			
		case XmGRID:
			rowindex++;
			if (rowindex > ncols) {
				rowindex = 1;
				x = ContainerMarginWidth(w);
				y += ch;
			} else {
				x += cw;
			}
			break;
		case XmNONE:
		default:
			break;
		}
	}

	contwid += 2 * ContainerMarginWidth(w);
	contht += 2 * ContainerMarginHeight(w);

	if (pwid)
		*pwid = contwid;
	if (pht)
		*pht = contht;
}

/*
 * FIX ME this is simplistic
 */
static void _XmContainerLayoutSimple(Widget w, Dimension *pwid, Dimension *pht)
{
	Dimension wid, ht;
	Cardinal i;
	Position x, y;

	wid = ContainerMarginWidth(w);
	ht = 0;

	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];
		if (XtIsManaged(child)) {
			wid += XtWidth(child) + ContainerMarginWidth(w);
			if (XtHeight(child) > ht)
				ht = XtHeight(child);
		}
	}

	ht += 2 * ContainerMarginHeight(w);

	if (pwid)
		*pwid = wid;
	if (pht)
		*pht = ht;

	x = ContainerMarginWidth(w);
	y = ContainerMarginHeight(w);

	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];
		if (XtIsManaged(child)) {
			_XmMoveObject(child, x, y);
			x += XtWidth(child) + ContainerMarginWidth(w);

			if (x > XtWidth(w) - ContainerMarginWidth(w)) {
				x = ContainerMarginWidth(w);
				if (XtHeight(child) < 20)
					y += 30;
				y += XtHeight(child);	/* FIX ME simplistic */
			}
		}
	}
}

/*
 * FIX ME this is simplistic
 */
static void _XmContainerLayoutDetail(Widget w, Dimension *pwid, Dimension *pht)
{
	Dimension wid, ht;
	Cardinal i;
	Position x, y;

	wid = ContainerMarginWidth(w);
	ht = 0;

	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];
		if (XtIsManaged(child)) {
			wid += XtWidth(child) + ContainerMarginWidth(w);
			if (XtHeight(child) > ht)
				ht = XtHeight(child);
		}
	}

	ht += 2 * ContainerMarginHeight(w);

	if (pwid)
		*pwid = wid;
	if (pht)
		*pht = ht;

	x = ContainerMarginWidth(w);
	y = ContainerMarginHeight(w);

	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];
		if (XtIsManaged(child)) {
			_XmMoveObject(child, x, y);
			x += XtWidth(child) + ContainerMarginWidth(w);

			if (x > XtWidth(w) - ContainerMarginWidth(w)) {
				x = ContainerMarginWidth(w);
				if (XtHeight(child) < 20)
					y += 30;
				y += XtHeight(child);	/* FIX ME simplistic */
			}
		}
	}
}

static void _XmContainerLayout(Widget w, Dimension *pwid, Dimension *pht)
{
	DEBUGOUT(_LtDebug(__FILE__, w, "_XmContainerLayout %s\n",
		(ContainerLayoutType(w) == XmDETAIL) ? "XmDETAIL" :
		(ContainerLayoutType(w) == XmSPATIAL) ? "XmSPATIAL" :
		(ContainerLayoutType(w) == XmOUTLINE) ? "XmOUTLINE" :
		"??"));

	switch (ContainerLayoutType(w)) {
	case XmDETAIL:
		_XmContainerLayoutDetail(w, pwid, pht);
		break;
	case XmOUTLINE:
		_XmContainerLayoutOutline(w, pwid, pht);
		break;
	case XmSPATIAL:
		_XmContainerLayoutSpatial(w, pwid, pht);
		break;
	default:
		_XmContainerLayoutSimple(w, pwid, pht);
		break;
	}
}

static XtGeometryResult
QueryGeometry(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
	Dimension		wid, ht;
	XtWidgetGeometry	g;

	/* FIX ME: Needs to be implemented */

	DEBUGOUT(_LtDebug(__FILE__, w, "XmContainer QueryGeometry\n"));
	g = *request;

	_XmContainerLayout(w, &wid, &ht);

	wid = (request->request_mode & CWWidth) ?
		(request->width < wid) ? wid : request->width : wid;
	ht = (request->request_mode & CWHeight) ?
		(request->height < ht) ? ht : request->height : ht;

	reply->request_mode = CWWidth | CWHeight;
	reply->width = (wid == 0) ? 1 : wid;
	reply->height = (ht == 0) ? 1 : ht;

	return _XmGMReplyToQueryGeometry(w, &g, reply);
}

static void Destroy(Widget w)
{
	int	i;

	ClearSelectedItems(w);
	for (i=0; i<MGR_NumChildren(w); i++) {
		/* Check first if they still have a constraint record */
		if (CoreConstraints(MGR_Children(w)[i]) && ! MGR_Children(w)[i]->core.being_destroyed) {
			XtFree((char *)CC_Node(MGR_Children(w)[i]));
			CC_Node(MGR_Children(w)[i]) = NULL;
		}
	}
}

/* composite */
static XtGeometryResult
GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
	DEBUGOUT(_LtDebug(__FILE__, w, "XmContainer GeometryManager\n"));

	/* FIX ME: Needs to be implemented */
	*reply = *request;
	return XtGeometryYes;
}

static void ChangeManaged(Widget w)
{
	DEBUGOUT(_LtDebug(__FILE__, w, "XmContainer ChangeManaged\n"));

	/* FIX ME: Needs to be implemented */
	_XmNavigChangeManaged(w);
	_XmContainerLayout(w, 0, 0);
}

static void _XmContainerExpandNode(Widget c)
{
	CwidNode		n;
	Widget			r;

	CC_OutlineState(c) = XmEXPANDED;

	r = CC_Related(c);
	if (r) {
		XtManageChild(r);
		XtVaSetValues(r,
			XmNoutlineState, XmEXPANDED,
			XmNlabelPixmap, ContainerExpandedStatePixmap(XtParent(r)),
			NULL);
	}

	for (n=CC_Node(c)->child_ptr; n; n=n->next_ptr) {
		if (CC_Related(n->widget_ptr)) {
			XtManageChild(CC_Related(n->widget_ptr));
		}
		XtManageChild(n->widget_ptr);
	}

	/* Geometry is handled in our caller !! */
}

static void _XmContainerUnmapSubtree(CwidNode n)
{
	CwidNode	c;
	Widget		w, r;

	DEBUGOUT(_LtDebug(__FILE__, n->widget_ptr, "_XmContainerUnmapSubtree\n"));
	if (!n)
		return;

	w = n->widget_ptr;
	if (CC_CWidType(w) == _XmIconButton)
		return;

	CC_OutlineState(w) = XmCOLLAPSED;
	r = CC_Related(w);
	if (r)
		XtVaSetValues(r,
			XmNoutlineState, XmCOLLAPSED,
			XmNlabelPixmap, ContainerCollapsedStatePixmap(XtParent(r)),
			NULL);

	for (c=n->child_ptr; c; c=c->next_ptr) {
		if (CC_CWidType(c->widget_ptr) != _XmIconButton) {
			Widget	r = CC_Related(c->widget_ptr);

			XtUnmanageChild(c->widget_ptr);
			if (r)
				XtUnmanageChild(r);
		}
		if (CC_CWidType(c->widget_ptr) != _XmIconButton)
			_XmContainerUnmapSubtree(c);
	}
}

/*
 * The pushbutton gadget gets toggled; need to open/close this part
 * of the tree. "Client" is the associated IconGadget.
 */
static void _XmContainerToggle(Widget w, XtPointer client, XtPointer call)
{
	Widget			b = (Widget) client,
				o = CC_Related(b);
	Dimension		wid, ht;
	XtGeometryResult	res;

	if (CC_OutlineState(o) == XmCOLLAPSED) {
		_XmContainerExpandNode(o);
	} else {
		/* Unmap children and their children */
		_XmContainerUnmapSubtree(CC_Node(o));
	}

	/* Query our ideal geometry */
	_XmContainerLayout(w, &wid, &ht);

	DEBUGOUT(_LtDebug2(__FILE__, w, o, "_XmContainerToggle: request %d %d\n", wid, ht));

	/* We'll need to request more real estate */
	res = XtMakeResizeRequest(w, wid, ht, &wid, &ht);
	if (res == XtGeometryYes) {
		XtWidth(w) = wid;
		XtHeight(w) = ht;
	}

	XClearWindow(XtDisplay(w), XtWindow(w));
}

/*
 * Attach widget CH to the right place in the tree structure.
 *	EP is the XmNentryParent.
 */
static void EntryParentHookup(Widget cw, Widget ch, Widget ep)
{
	Widget	prev = 0, nxt = 0;

	/* Need to initialize PositionIndex. FIX ME */
	if (CC_PositionIndex(ch) == 0) {
		int	i, m;

		/* Find children with the same EntryParent */
		/* Get the maximum PositionIndex among them */
		m = -1;
		for (i=0; i<MGR_NumChildren(cw); i++) {
			Widget c = MGR_Children(cw)[i];

			if (CC_CWidType(c) == _XmIconButton)
				continue;

			if (CC_EntryParent(c) == ep && CC_PositionIndex(c) > m) {
				m = CC_PositionIndex(c);
				prev = c;
			}
		}

		/* Assign one more than the maximum found */
		if (m >= 0) {
			CC_PositionIndex(ch) = m + 1;
			DEBUGOUT(_LtDebug2(__FILE__, ch, prev,
				"positionIndex %d\n", m+1));
		}
	} else {
		int	i, m;

		/* Find the child with the same EntryParent that has the largest
		 * PositionIndex smaller than ours.
		 */
		m = -1;
		for (i=0; i<MGR_NumChildren(cw); i++) {
			Widget	c = MGR_Children(cw)[i];
			int	p = CC_PositionIndex(c);

			if (CC_CWidType(c) == _XmIconButton)
				continue;
			if (CC_EntryParent(c) == ep && p < CC_PositionIndex(ch) && p > m) {
				prev = c;
				m = p;
			}
		}
	}

	if (CC_OutlineState(ch) == 0xFF) {
		/* This is the value we pass when creating a "folder" icon */
		CC_CWidType(ch) = _XmIconButton;
	} else {
		CC_CWidType(ch) = _XmChild;
	}

	/* Build the tree structure if OUTLINE */
	CC_Node(ch) = NULL;
	CC_Related(ch) = NULL;

	if (ContainerLayoutType(cw) == XmOUTLINE) {
		CC_Node(ch) = (CwidNode)XtMalloc(sizeof(XmCwidNodeRec));
		CC_Next(ch) = CC_Prev(ch) = CC_Child(ch) = NULL;

		CC_Widget(ch) = ch;
		
		if (CC_EntryParent(ch)) {
			CC_Parent(ch) = CC_Node(CC_EntryParent(ch));
			DEBUGOUT(_LtDebug2(__FILE__, cw, ch,
				"Constraint EntryParentHookup: parent is %s %p\n",
				XtName(CC_EntryParent(ch)),
				CC_EntryParent(ch)));
		} else {
			CC_Parent(ch) = 0;
		}

		if (prev) {
			if (CC_Next(prev)) {	/* Need to do some fixing */
				/* Now : prev -> nxt , to be prev -> this -> nxt */
				nxt = CC_Next(prev)->widget_ptr;

				CC_Next(ch) = CC_Node(nxt);
				CC_Prev(nxt) = CC_Node(ch);
			}
			CC_Prev(ch) = CC_Node(prev);
			CC_Next(prev) = CC_Node(ch);
		}
	}

	/* First/last */
	if (ContainerFirstNode(cw) == 0) {
		ContainerFirstNode(cw) = CC_Node(ch);
		ContainerLastNode(cw) = CC_Node(ch);
	}

	DEBUGOUT(_LtDebug2(__FILE__, cw, ch,
		"XmContainer EntryParentHookup (parent %p PI %d X %d Y %d)\n",
		CC_EntryParent(ch),
		CC_PositionIndex(ch),
		CC_UserX(ch),
		CC_UserY(ch)));

	/* Create a button for my parent if it doesn't have any yet */
	if (ContainerLayoutType(cw) == XmOUTLINE
			&& CC_CWidType(ch) == _XmChild
			&& CC_Node(ch)
			&& CC_Parent(ch)) {
		Widget	parent = CC_Parent(ch)->widget_ptr;

		if (!CC_Related(parent)) {
	 		Arg	al[5];
			int	ac = 0;
			Widget	b;

			if (CC_OutlineState(parent) == XmCOLLAPSED) {
				XtSetArg(al[ac], XmNlabelPixmap, ContainerCollapsedStatePixmap(cw)); ac++;
			} else {
				XtSetArg(al[ac], XmNlabelPixmap, ContainerExpandedStatePixmap(cw)); ac++;
			}
			XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
			XtSetArg(al[ac], XmNoutlineState, (XtPointer)0xFF); ac++;
			CC_Related(parent) =
			b = XmCreatePushButtonGadget(cw, "icon", al, ac);
			CC_Related(b) = parent;
			XtManageChild(b);
			CC_CWidType(b) = _XmIconButton;

			/*
			 * Allocate a node for the new button,
			 * and insert it in the tree.
			 * This is mucho easier here which is why we
			 * pull the 0xFF outlineState trick above.
			 *
			 * Note that the _XmIconButton is only attached to the node
			 * that it belongs to, it doesn't have previous/next pointers.
			 */
			CC_Node(b) = (CwidNode)XtMalloc(sizeof(XmCwidNodeRec));

			CC_Next(b) = CC_Prev(b) = NULL;
			CC_Child(b) = NULL;
			CC_Parent(b) = CC_Node(parent);

			CC_Widget(b) = b;
#if 0
			/* Doesn't currently seem to work FIX ME */
			XtAddCallback(b, XmNactivateCallback,
				_XmContainerToggle, (XtPointer)parent);
#endif
		}

		/* Obviously this means the parent didn't have a child yet */
		if (CC_Child(parent) == NULL)
			CC_Child(parent) = CC_Node(ch);
	}
}

#include <stdio.h>

/*
 * Take a child widget out of the tree.
 *	This is often called with w->core.being_destroyed == True.
 *	FIX ME currently there is obviously still something wrong here :
 *	exactly what needs to be done for those widgets ?
 */
static void EntryParentClear(Widget cw, Widget ch)
{
	DEBUGOUT(_LtDebug2(__FILE__, cw, ch, "EntryParentClear\n"));

	/* Maybe this is the first node */
	if (ContainerFirstNode(cw) && ContainerFirstNode(cw)->widget_ptr == ch) {
		ContainerFirstNode(cw) = CC_Next(ch);
	}

	if (ch->core.being_destroyed) {
		DEBUGOUT(_LtDebug2(__FILE__, cw, ch, "EntryParentClear ZOMBIE %p\n", ch));
		return;
	}
	if (CC_CWidType(ch) == _XmIconButton)
		return;
	if (CC_Child(ch)) {
		_XmWarning(ch, "EntryParentClear: node has children, this should not happen\n");
	}

	/*
	 * Move out of sight. Can't unmanage because we wouldn't know
	 * when/whether to manage again.
	 */
	_XmMoveObject(ch, -100-XtWidth(ch), -100-XtHeight(ch));

	/* Remove link from the parent if this is its first child. */
	if (CC_Parent(ch)) {
		Widget	p = CC_Parent(ch)->widget_ptr;
		if (CC_Child(p) && CC_Child(p)->widget_ptr == ch) {
			CC_Child(p) = CC_Next(ch);
		}
	}

	/* Remove previous/next links */
	if (CC_Next(ch) && CC_Prev(ch)) {	/* Have both CC_Next and CC_Prev */
		Widget	n = CC_Next(ch)->widget_ptr,
			p = CC_Prev(ch)->widget_ptr;
		CC_Next(p) = CC_Node(n);
		CC_Prev(n) = CC_Node(p);

	} else if (CC_Next(ch)) {		/* Only a CC_Next */
		Widget	n = CC_Next(ch)->widget_ptr;
		CC_Prev(n) = NULL;
	} else if (CC_Prev(ch)) {		/* Only a CC_Prev */
		Widget	p = CC_Prev(ch)->widget_ptr;
		CC_Next(p) = NULL;
	} else {				/* Neither : nothing to do */
	}

	/* Remove IconButton node if there's one related to this widget. */
	if (CC_Related(ch)) {
		Widget	r = CC_Related(ch);

		DEBUGOUT(_LtDebug2(__FILE__, ch, r, "Related icon-button %p being destroyed\n", r));

		CC_Related(r) = NULL;
		CC_Next(r) = CC_Prev(r) = CC_Parent(r) = CC_Child(r) = NULL;
		CC_Node(r) = NULL;
		CC_Related(ch) = NULL;

		XtDestroyWidget(r);
	}

	CC_Next(ch) = CC_Prev(ch) = NULL;
	XtFree((char *)CC_Node(ch));
	CC_Node(ch) = NULL;
}

/* constraint */
/* FIX ME must maintain ContainerLastNode */
static void
ConstraintInitialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	Widget				cw = XtParent(new_w), prev = NULL;
/*	XmContainerConstraintPtr	con = (XmContainerConstraintPtr)CoreConstraints(new_w); */
	Dimension			wid, ht;
	XtGeometryResult		res;

	DEBUGOUT(_LtDebug2(__FILE__, cw, new_w, "ConstraintInitialize\n"));
	DEBUGOUT(
		if (CC_EntryParent(new_w)) {
		_LtDebug2(__FILE__, new_w, CC_EntryParent(new_w),
			"EntryParent\n");
	});

	CC_Node(new_w) = NULL;

	/* Need to initialize PositionIndex. FIX ME */
	if (CC_PositionIndex(new_w) == 0) {
		int	i, m;

		/* Find children with the same EntryParent */
		/* Get the maximum PositionIndex among them */
		m = -1;
		for (i=0; i<MGR_NumChildren(cw); i++) {
			Widget c = MGR_Children(cw)[i];

			if (CC_CWidType(c) == _XmIconButton)
				continue;

			if (CC_EntryParent(c) == CC_EntryParent(new_w)
					&& CC_PositionIndex(c) > m) {
				m = CC_PositionIndex(c);
				prev = c;
			}
		}

		/* Assign one more than the maximum found */
		if (m >= 0) {
			CC_PositionIndex(new_w) = m + 1;
			DEBUGOUT(_LtDebug2(__FILE__, new_w, prev,
				"positionIndex %d\n", m+1));
		}
	}

	if (CC_OutlineState(new_w) == 0xFF) {
		/* This is the value we pass when creating a "folder" icon */
		DEBUGOUT(_LtDebug2(__FILE__, cw, new_w, "Yes !\n"));
		CC_CWidType(new_w) = _XmIconButton;
	} else {
		CC_CWidType(new_w) = _XmChild;
	}

	/* Build the tree structure if OUTLINE */
	CC_Node(new_w) = NULL;
	CC_Related(new_w) = NULL;

	EntryParentHookup(cw, new_w, CC_EntryParent(new_w));

	_XmContainerLayout(cw, &wid, &ht);

	DEBUGOUT(_LtDebug2(__FILE__, cw, new_w,
		"ContainerConstraintInitialise: geo %d.%d -> %d.%d\n",
		XtWidth(cw), XtHeight(cw), wid, ht));

	if (XtWidth(cw) < wid || XtHeight(cw) < ht) {
		if (wid < XtWidth(cw))
			wid = XtWidth(cw);
		if (ht < XtHeight(cw))
			ht = XtHeight(cw);
		res = XtMakeResizeRequest(cw, wid, ht, &wid, &ht);
		if (res == XtGeometryYes) {
			XtWidth(cw) = wid;
			XtHeight(cw) = ht;
		}
	}
}

static void ConstraintDestroy(Widget w)
{
	Widget			cw = XtParent(w);

	DEBUGOUT(_LtDebug2(__FILE__, cw, w, "XmContainer ConstraintDestroy\n"));

	if (ItemIsSelected(cw, w))
		RemoveSelectedItem(cw, w);
	EntryParentClear(cw, w);

	/* Remove graphics leftovers by redrawing completely. */
	if (XtWindow(cw))
		XClearWindow(XtDisplay(cw), XtWindow(cw));
}

static Boolean
ConstraintSetValues(Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	Widget	c = XtParent(new_w);
	Boolean	relayout = False;


	DEBUGOUT(_LtDebug2(__FILE__, c, new_w, "XmContainer ConstraintSetValues\n"));
	/* FIX ME: Needs to be implemented */
#if 0
	if (CC_OutlineState(new_w) != CC_OutlineState(current)) {
		Pixmap	p;

		if (CC_OutlineState(new_w) == XmCOLLAPSED)
			p = ContainerCollapsedStatePixmap(c);
		else
			p = ContainerExpandedStatePixmap(c);

		XtVaSetValues(new_w, XmNlabelPixmap, p, NULL);
	}
#endif

	/* Add the XmNentryParent to an already existing widget */
	if (CC_EntryParent(new_w) != CC_EntryParent(current)) {
		/* Remove the widget from the old place in the tree. */
		EntryParentClear(c, new_w);

		/* Hook up the widget in the new place in the tree */
		EntryParentHookup(c, new_w, CC_EntryParent(new_w));

		relayout = True;
	}
#if 0
	/* This doesn't belong here */
	if ((ContainerLargeCellWidth(new_w) != ContainerLargeCellWidth(current))
		|| (ContainerLargeCellHeight(new_w) != ContainerLargeCellHeight(current))
		|| (ContainerSmallCellWidth(new_w) != ContainerSmallCellWidth(current))
		|| (ContainerSmallCellHeight(new_w) != ContainerSmallCellHeight(current))) {
		relayout = True;
	}
#endif

	if (relayout)
		_XmContainerLayout(c, NULL, NULL);
	return relayout;
}

/*
 * XmContainerGetItemChildren allocates a WidgetList and stores within it
 * the widget IDs of all widgets that have item specified as the value of
 * their XmNentryParent resource.
 * The application programmer is responsible for freeing the allocated
 * WidgetList using XtFree. The number of widget IDs returned in item_children
 * is returned by the function. If no widgets specify item as the value of
 * their XmNentryParent resource, the function returns zero and
 * item_children is left unchanged.
 */
int XmContainerGetItemChildren(Widget w, Widget item, WidgetList *item_children)
{
	Widget	*l;
	int	i, j, num;

	for (i=0, num=0; i<MGR_NumChildren(w); i++)
		if (CC_EntryParent(MGR_Children(w)[i]) == item)
			num++;
	if (num == 0)
		return 0;

	l = (Widget *)XtCalloc(num + 1, sizeof(Widget));
	for (i=0, j=0; i < MGR_NumChildren(w) && j < num; i++)
		if (CC_EntryParent(MGR_Children(w)[i]) == item)
			l[j++] = MGR_Children(w)[i];
	*item_children = l;

	return num;
}

void XmContainerRelayout(Widget w)
{
	_XmWarning(w, "XmContainerRelayout(): not yet implemented!");
}

void XmContainerReorder(Widget w, WidgetList cwid_list, int cwid_count)
{
	_XmWarning(w, "XmContainerReorder(): not yet implemented!");
}

Boolean XmContainerCut(Widget w, Time timestamp)
{
	_XmWarning(NULL, "XmContainerCut(): not yet implemented!");
	return False;
}

/*
 * XmContainerCopy copies the primary selected container items to the clipboard.
 * This routine calls the XmNconvertCallback procedures, possibly multiple times,
 * with the selection member of the XmConvertCallbackStruct set to CLIPBOARD and
 * with the parm member set to XmCOPY.
 *
 * container	Specifies the Container widget ID.
 * timestamp	Specifies the server time at which to modify the selection value.
 *
 * The function returns False in the following cases:
 *	if the primary selection is NULL,
 *	if the widget does not own the primary selection, or
 *	if the function is unable to gain ownership of the clipboard selection.
 * Otherwise, it returns True.
 */
Boolean XmContainerCopy(Widget w, Time timestamp)
{
	_XmWarning(w, "XmContainerCopy(): not yet implemented!");
	return False;
}

/*
 * XmContainerPaste requests data transfer from the clipboard selection
 * to the Container. This routine calls the widget's XmNdestinationCallback
 * procedures with the selection member of the XmDestinationCallbackStruct
 * set to CLIPBOARD and with the operation member set to XmCOPY. The Container
 * widget itself performs no transfers; the XmNdestinationCallback procedures
 * are responsible for inserting the clipboard selection and for taking any
 * related actions.
 *
 * container	Specifies the Container widget ID.
 *
 * The function returns False if no data transfer takes place.
 * Otherwise, it returns True.
 */
Boolean XmContainerPaste(Widget w)
{
	_XmWarning(w, "XmContainerPaste(): not yet implemented!");
	return False;
}

Boolean XmContainerCopyLink(Widget w, Time timestamp)
{
	_XmWarning(w, "XmContainerCopyLink(): not yet implemented!");
	return False;
}

/*
 * XmContainerPasteLink requests data transfer from the clipboard selection
 * to the Container. This routine calls the widget's XmNdestinationCallback
 * procedures with the selection member of the XmDestinationCallbackStruct
 * set to CLIPBOARD and with the operation member set to XmLINK. The Container
 * widget itself performs no transfers; the XmNdestinationCallback procedures
 * are responsible for inserting the link to the clipboard selection and for
 * taking any related actions.
 */
Boolean XmContainerPasteLink(Widget w)
{
	_XmWarning(w, "XmContainerPasteLink(): not yet implemented!");
	return False;
}

static void
_ContainerTrait_GetValues(Widget container, XmContainerData d)
{
	DEBUGOUT(_LtDebug(__FILE__, container, "_ContainerTrait_GetValues\n"));

	if (d->valueMask & ContDetailOrder) {
		d->detail_order = ContainerDetailOrder(container);
		d->detail_order_count = ContainerDetailOrderCount(container);
	}
	if (d->valueMask & ContDetailTabList) {
		d->detail_tablist = ContainerDetailTablist(container);
	}
	if (d->valueMask & ContFirstColumnWidth) {
		d->first_column_width = ContainerFirstColWidth(container);
	}
	if (d->valueMask & ContSelectionMode) {
#if 0
		/* FIX ME what is this ? */
		d->selection_mode = ContainerSelectionMode(container);
#endif
	}
	if (d->valueMask & ContSelectColor) {
		d->select_color = ContainerSelectColor(container);
	}
}

/*
 * Figure out which object the user 'hit'
 */
static Widget HitObject(Widget cont, Position x, Position y)
{
	/* FIX ME this is currently very simplistic */
	int	i;

	for (i=0; i<MGR_NumChildren(cont); i++) {
		Widget child = MGR_Children(cont)[i];

		if (XtX(child) <= x && x <= XtX(child) + XtWidth(child)
			&& XtY(child) <= y && y <= XtY(child) + XtHeight(child)) {

			return child;
		}
	}
	return NULL;
}

/*
 * Actions
 *
 * ContainerActivate() calls XmNdefaultActionCallback with reason XmCR_DEFAULT_ACTION.
 */
static void ContainerActivate(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	XmContainerSelectCallbackStruct	cbs;
	Widget				fw;
#if 1
	DEBUGOUT(_LtDebugAction(__FILE__, w, "XmContainer ContainerActivate", params, num_params));
#endif
	/* This should probably be the technique to get this ...
	fw = XmGetFocusWidget(w);
	** */

	fw = ContainerIconHeader(w);	/* Hack */
	if (!fw)
		return;				/* FIX ME is this the right action ? */

	if (CC_CWidType(fw) == _XmIconButton) {
		_XmContainerToggle(w, (XtPointer)fw, NULL);
	} else {
		/* */
		cbs.reason = XmCR_DEFAULT_ACTION;
		cbs.event = event;
		cbs.selected_items = NULL;	/* FIX ME */
		cbs.selected_item_count = 0;	/* FIX ME */
		cbs.auto_selection_type = 0;	/* FIX ME */

		XtCallCallbackList(w, ContainerDefaultActionCallback(w), (XtPointer)&cbs);
	}
}

/*
 * This function should be used in the Action event handlers to
 * figure out whether to fold/expand the tree or to do action
 * processing.
 */
static int _XmContainerToggleEvent(Widget w, XEvent *event)
{
	Widget	fw = ContainerIconHeader(w);

	if (fw && CC_CWidType(fw) == _XmIconButton) {
		_XmContainerToggle(w, (XtPointer)fw, NULL);
		return False;
	} else {
		return True;
	}

	return True;	/* Means still have to treat this */	
}

/*
 * ContainerBeginExtend()
 *	Returns if XmNselectionPolicy is XmSINGLE_SELECT or XmBROWSE_SELECT.
 *	Returns if XmNlayoutType is XmSPATIAL.
 *	Otherwise, this action sets the selection state of all items between the
 *	anchor item and the item under the pointer to the selection state of the
 *	anchor item. The location cursor is moved to the item under the pointer.
 *	If XmNautomaticSelection is XmAUTO_SELECT, the XmNselectionCallback(s) is
 *	called with either XmCR_MULTIPLE_SELECT or XmCR_EXTENDED_SELECT as the
 *	reason depending on XmNselectionPolicy, and with auto_selection_type
 *	XmAUTO_CHANGE.
 */
static void
ContainerBeginExtend(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	Widget	hit;

	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerBeginExtend", params, num_params));

	if (ContainerSelectionPolicy(w) == XmSINGLE_SELECT
			|| ContainerSelectionPolicy(w) == XmBROWSE_SELECT
			|| ContainerLayoutType(w) == XmSPATIAL)
		return;

	hit = HitObject(w, event->xbutton.x, event->xbutton.y);

	if (ItemIsSelected(w, ContainerAnchorCWid(w))) {
		SelectItemRange(w, ContainerAnchorCWid(w), hit);
	} else {
		UnselectItemRange(w, ContainerAnchorCWid(w), hit);
	}

	/* FIX ME set the location cursor */

	if (ContainerAutomaticSelection(w) == XmAUTO_SELECT) {
		XmContainerSelectCallbackStruct	cbs;
	
		if (ContainerSelectionPolicy(w) == XmEXTENDED_SELECT)
			cbs.reason = XmCR_EXTENDED_SELECT;
		else
			cbs.reason = XmCR_MULTIPLE_SELECT;

		cbs.auto_selection_type = XmAUTO_CHANGE;
		cbs.event = event;
		cbs.selected_items = ContainerSelectedItems(w);
		cbs.selected_item_count = ContainerSelectedItemCount(w);
		XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
	}
}

/*
 * ContainerBeginSelect() :
 *	If this is a second ContainerBeginSelect() action that has occurred
 *	within the time specified by the display's multiclick time, this
 *	action calls XmNdefaultActionCallback with reason XmCR_DEFAULT_ACTION
 *	and returns.
 *	Otherwise, processing depends on the value of XmNselectionPolicy as follows: 
 *	XmSINGLE_SELECT
 *		This action deselects all items and toggles the item (if any) under the pointer. 
 *	XmBROWSE_SELECT
 *		This action deselects all items and toggles the item (if any) under the pointer.
 *		This item is now the anchor item for further selection. If XmNautomaticSelection
 *		is XmAUTO_SELECT and a change in any item's selection state is made, the
 *		XmNselectionCallback(s) is called with reason XmCR_BROWSE_SELECT and
 *		auto_selection_type XmAUTO_BEGIN.
 *	XmMULTIPLE_SELECT
 *		If the pointer is over an item and XmNselectionTechnique is not XmMARQUEE,
 *		this action toggles the selection state of that item. The item becomes the anchor
 *		item for further selection. If XmNselectionTechnique is XmMARQUEE,
 *		XmMARQUEE_EXTEND_START, or XmMARQUEE_EXTEND_BOTH, this action sets
 *		the start point for the Marquee rectangle. If XmNselectionTechnique is
 *		XmMARQUEE_EXTEND_START or XmMARQUEE_EXTEND_BOTH and the pointer is over an item,
 *		this action draws the Marquee rectangle around the item. If XmNautomaticSelection
 *		is XmAUTO_SELECT, the XmNselectionCallback(s) is called with reason
 *		XmCR_MULTIPLE_SELECT and auto_selection_type XmAUTO_BEGIN.
 *	XmEXTENDED_SELECT
 *		All items are first deselected. Processing is then identical to the case where
 *		XmNselectionPolicy is XmMULTIPLE_SELECT, except that XmCR_EXTENDED_SELECT is the
 *		callback reason given if XmNselectionCallback is called. 
 */
static void
ContainerBeginSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	Time	mctime = XtGetMultiClickTime(XtDisplay(w));
	Widget	hit;

	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerBeginSelect", params, num_params));
	DEBUGOUT(_LtDebug(__FILE__, w, "\tEvent at %d %d\n", event->xbutton.x, event->xbutton.y));

	/* If this is the second ContainerBeginSelect within the multiclick time,
	 * then call the default action callback */
	if (ContainerLastClickTime(w) &&
			event->xbutton.time - ContainerLastClickTime(w) < mctime) {
		XmContainerSelectCallbackStruct	cbs;

		cbs.reason = XmCR_DEFAULT_ACTION;
		cbs.event = event;
		cbs.selected_items = ContainerSelectedItems(w);
		cbs.selected_item_count = ContainerSelectedItemCount(w);
		cbs.auto_selection_type = 0;	/* FIX ME */

		XtCallCallbackList(w, ContainerDefaultActionCallback(w), (XtPointer)&cbs);
		return;
	}

	ContainerLastClickTime(w) = event->xbutton.time;
	hit = HitObject(w, event->xbutton.x, event->xbutton.y);
	ContainerIconHeader(w) = hit;	/* FIX ME this resource probably serves another puspose */

	DEBUGOUT(_LtDebug(__FILE__, w, "Hit '%s'\n",
		hit ? XtName(hit) : "(nothing)"));

	/* FIX ME another hack */
	if (hit && CC_CWidType(hit) == _XmIconButton) {
#if 1
		/* It's probably not as simple as this */
		XtCallActionProc(w, "ManagerGadgetActivate", event, NULL, 0);
#endif
	}

	switch (ContainerSelectionPolicy(w)) {
	case XmSINGLE_SELECT:
		ClearSelectedItems(w);
		AddSelectedItem(w, hit);
		break;
	case XmBROWSE_SELECT:
		ClearSelectedItems(w);
		if (hit) {
			AddSelectedItem(w, hit);
			ContainerAnchorCWid(w) = hit;
			if (ContainerAutomaticSelection(w) == XmAUTO_SELECT) {
				XmContainerSelectCallbackStruct cbs;

				cbs.reason = XmBROWSE_SELECT;
				cbs.auto_selection_type = XmAUTO_BEGIN;
				cbs.event = event;
				cbs.selected_items = ContainerSelectedItems(w);
				cbs.selected_item_count = ContainerSelectedItemCount(w);
				XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
			}			
		}
		break;
	default:
	case XmEXTENDED_SELECT:
		ClearSelectedItems(w);
		/* Fall through !! */
	case XmMULTIPLE_SELECT:
		if (hit && ContainerSelectionTechnique(w) != XmMARQUEE) {
			/* Toggle selection state of this item */
			if (ItemIsSelected(w, hit))
				RemoveSelectedItem(w, hit);
			else
				AddSelectedItem(w, hit);
			ContainerAnchorCWid(w) = hit;
		}
		if (ContainerSelectionTechnique(w) == XmMARQUEE
			|| ContainerSelectionTechnique(w) == XmMARQUEE_EXTEND_START
			|| ContainerSelectionTechnique(w) == XmMARQUEE_EXTEND_BOTH) {
			MarqueeStart(w, event);
		}
		if (hit && (ContainerSelectionTechnique(w) == XmMARQUEE_EXTEND_START
			|| ContainerSelectionTechnique(w) == XmMARQUEE_EXTEND_BOTH)) {
			/* FIX ME */
		}
		if (ContainerAutomaticSelection(w) == XmAUTO_SELECT) {
			XmContainerSelectCallbackStruct cbs;

			if (ContainerSelectionPolicy(w) == XmEXTENDED_SELECT)
				cbs.reason = XmCR_EXTENDED_SELECT;
			else
				cbs.reason = XmCR_MULTIPLE_SELECT;
			cbs.auto_selection_type = XmAUTO_BEGIN;
			cbs.event = event;
			cbs.selected_items = ContainerSelectedItems(w);
			cbs.selected_item_count = ContainerSelectedItemCount(w);
			XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
		}
	}
}

static void
ContainerBeginToggle(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerBeginToggle", params, num_params));
}

/*
 * ContainerButtonMotion() :
 *	Processing depends on the value of XmNselectionPolicy, as follows: 
 *	XmSINGLE_SELECT
 *		This action simply returns to the caller. 
 *	XmBROWSE_SELECT
 *		Simply returns if this action follows a ContainerBeginExtend()
 *		action or ContainerBeginToggle() action. 
 *		If the pointer is no longer over the current anchor item, this
 *		action toggles the current anchor item and then toggles the item
 *		under the pointer (if any) and makes it the new anchor item for
 *		further processing. If XmNautomaticSelection is XmAUTO_SELECT and
 *		a change in any item's selection state is made, the
 *		XmNselectionCallback(s) is called with reason XmCR_BROWSE_SELECT
 *		and auto_selection_type XmAUTO_MOTION.
 *	XmMULTIPLE_SELECT
 *		If a previous action has set a Marquee rectangle start point, this
 *		action draws the Marquee rectangle between the current pointer
 *		position and the Marquee start point. If the XmNselectionTechnique
 *		is XmMARQUEE_EXTEND_BOTH and the pointer is over an item, the end
 *		point of the Marquee rectangle is extended to include the item. The
 *		selection states of all items within the Marquee rectangle are
 *		toggled to match the state of the anchor item.
 *		If no Marquee rectangle start point is set and the pointer is
 *		over an item, processing depends on the XmNlayoutType resource.
 *		The anchor item from the previous action is used. If XmNlayoutType
 *		is XmSPATIAL, the selection state of the item under the pointer is
 *		toggled to match the selection state of the anchor item. If
 *		XmNlayoutType is XmOUTLINE or XmDETAIL, the selection state of all
 *		items between the anchor item and the item under the pointer are
 *		toggled to match the selection state of the anchor item. 
 *		If XmNautomaticSelection is XmAUTO_SELECT and a change in any item's
 *		selection state is made, the XmNselectionCallback(s) is called with
 *		reason XmCR_MULTIPLE_SELECT and auto_selection_type XmAUTO_MOTION.
 *	XmEXTENDED_SELECT
 *		Processing is identical to the case where XmNselectionPolicy is
 *		XmMULTIPLE_SELECT, except that XmCR_EXTENDED_SELECT is the callback
 *		reason given if XmNselectionCallback is called. 
 *
 * Note : the fake function is to make the distinction between a call from
 *	ContainerEndSelect() and as the real ContainerButtonMotion() handler.
 *	The former case doesn't call the XmNselectionCallback, the latter does.
 */
static Boolean HandleContainerButtonMotion(Boolean doit,
	Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	Widget		hit;
	Position	x, y;
	Boolean		ChangedSelection = False;

	DEBUGOUT(_LtDebugAction(__FILE__, w, "HandleContainerButtonMotion", params, num_params));

	switch (ContainerSelectionPolicy(w)) {
	case XmSINGLE_SELECT:
		return False;
	case XmBROWSE_SELECT:	/* FIX ME */
		break;
	case XmMULTIPLE_SELECT:
	case XmEXTENDED_SELECT:	/* This is the default */
	default:
		if (ContainerMarqueeMode(w)) {	/* If there's a marquee rectangle start */
			/* FIX ME */
		} else {	/* No marquee rectangle start */
			/* If the pointer is over an item */
			switch (event->type) {
			case MotionNotify:
				x = event->xmotion.x;
				y = event->xmotion.y;
				break;
			case ButtonPress:
			case ButtonRelease:
			default:	/* FIX ME */
				x = event->xbutton.x;
				y = event->xbutton.y;
				break;
			}
			hit = HitObject(w, x, y);
			DEBUGOUT(_LtDebug2(__FILE__, w, hit, "Yow ContainerButtonMotion\n"));
			switch (ContainerLayoutType(w)) {
			case XmSPATIAL:
				/* FIX ME */
			case XmOUTLINE:
			case XmDETAIL:
			default:
				if (hit) {
					if (ItemIsSelected(w, ContainerAnchorCWid(w))) {
						SelectItemRange(w, ContainerAnchorCWid(w), hit);
					} else {
						UnselectItemRange(w, ContainerAnchorCWid(w), hit);
					}
					ChangedSelection = True;
				}
			}
			
		}
		if (doit && ChangedSelection && ContainerAutomaticSelection(w) == XmAUTO_SELECT) {
			XmContainerSelectCallbackStruct	cbs;

			cbs.reason = XmCR_MULTIPLE_SELECT;
			cbs.event = event;
			cbs.auto_selection_type = XmAUTO_MOTION;
			cbs.selected_item_count = 0;
			cbs.selected_items = 0;

			XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
		}
	}
	return ChangedSelection;
}

static void
ContainerButtonMotion(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	(void) HandleContainerButtonMotion(True, w, event, params, num_params);
}

static void
ContainerCancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerCancel", params, num_params));
}

static void
ContainerDeselectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerDeselectAll", params, num_params));
}

/*
 *	ContainerEndExtend() :
 *
 *	Simply returns if XmNselectionPolicy is XmSINGLE_SELECT or XmBROWSE_SELECT.
 *	Simply returns if XmNlayoutType is XmSPATIAL.
 *
 *	Otherwise, if XmNautomaticSelection is XmNO_AUTO_SELECT,
 *	XmNselectionCallback(s) is called with either XmCR_MULTIPLE_SELECT or
 *	XmCR_EXTENDED_SELECT as the reason depending on XmNselectionPolicy.
 *
 *	If XmNautomaticSelection is XmAUTO_SELECT and no change is made in any item's
 *	selection state by this action, XmNselectionCallback(s) is called with either
 *	XmCR_MULTIPLE_SELECT or XmCR_EXTENDED_SELECT as the reason depending
 *	on XmNselectionPolicy and auto_selection_type XmAUTO_CHANGE.
 *
 *	If XmNautomaticSelection is XmAUTO_SELECT and this action makes no change in any
 *	item's selection state, XmNselectionCallback(s) is called with either
 *	XmCR_MULTIPLE_SELECT or XmCR_EXTENDED_SELECT as the reason depending
 *	on XmNselectionPolicy and auto_selection_type XmAUTO_NO_CHANGE.
 */
static void
ContainerEndExtend(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	XmContainerSelectCallbackStruct	cbs;

	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerEndExtend", params, num_params));

	if (ContainerSelectionPolicy(w) == XmSINGLE_SELECT
		|| ContainerSelectionPolicy(w) == XmBROWSE_SELECT
		|| ContainerLayoutType(w) == XmSPATIAL)
		return;

	if (ContainerAutomaticSelection(w) == XmNO_AUTO_SELECT) {
		if (ContainerSelectionPolicy(w) == XmMULTIPLE_SELECT)
			cbs.reason = XmCR_MULTIPLE_SELECT;
		else
			cbs.reason = XmCR_EXTENDED_SELECT;
		cbs.event = event;
		cbs.auto_selection_type = XmAUTO_MOTION;
		cbs.selected_item_count = 0;
		cbs.selected_items = 0;
		XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
	} else if (ContainerAutomaticSelection(w) == XmAUTO_SELECT) {
		if (0 /* FIX ME, if we've changed the selection */) {
			if (ContainerSelectionPolicy(w) == XmMULTIPLE_SELECT)
				cbs.reason = XmCR_MULTIPLE_SELECT;
			else
				cbs.reason = XmCR_EXTENDED_SELECT;
			cbs.event = event;
			cbs.auto_selection_type = XmAUTO_CHANGE;
			cbs.selected_item_count = ContainerSelectedItemCount(w);
			cbs.selected_items = ContainerSelectedItems(w);
			XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
		} else {	/* Haven't changed the selection */
			if (ContainerSelectionPolicy(w) == XmMULTIPLE_SELECT)
				cbs.reason = XmCR_MULTIPLE_SELECT;
			else
				cbs.reason = XmCR_EXTENDED_SELECT;
			cbs.event = event;
			cbs.auto_selection_type = XmAUTO_NO_CHANGE;
			cbs.selected_item_count = ContainerSelectedItemCount(w);
			cbs.selected_items = ContainerSelectedItems(w);
			XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
		}
	}
}

/*
 * ContainerEndSelect() :
 *	Processing depends on the value of XmNselectionPolicy, as follows:
 *	XmSINGLE_SELECT
 *		This action calls XmNselectionCallback with reason XmCR_SINGLE_SELECT. 
 *	XmBROWSE_SELECT
 *		If the pointer is no longer over the current anchor item,
 *		this action toggles the current anchor item and then toggles the item
 *		under the pointer (if any). If XmNautomaticSelection is XmNO_AUTO_SELECT,
 *		the XmNselectionCallback(s) is called with reason XmCR_BROWSE_SELECT.
 *		If XmNautomaticSelection is XmAUTO_SELECT and a change in any item's
 *		selection state is made, XmNselectionCallback(s) is called with reason
 *		XmCR_BROWSE_SELECT and auto_selection_type XmAUTO_CHANGE. If
 *		XmNautomaticSelection is XmAUTO_SELECT and no change is made in any
 *		item's selection state by this action, XmNselectionCallback(s) is
 *		called with reason XmCR_BROWSE_SELECT and auto_selection_type
 *		XmAUTO_NO_CHANGE. 
 *	XmMULTIPLE_SELECT
 *		This action first performs the same processing as the
 *		ContainerButtonMotion() action, except that XmNselectionCallback
 *		is not called. If XmNautomaticSelection is XmNO_AUTO_SELECT, the
 *		XmNselectionCallback(s) is called with reason XmCR_MULTIPLE_SELECT.
 *		If XmNautomaticSelection is XmAUTO_SELECT and a change in any item's
 *		selection state is made, the XmNselectionCallback(s) is called with
 *		reason XmCR_MULTIPLE_SELECT and auto_selection_type XmAUTO_CHANGE.
 *		If XmNautomaticSelection is XmAUTO_SELECT and this action makes no
 *		change in any item's selection state, XmNselectionCallback(s) is
 *		called with reason XmCR_MULTIPLE_SELECT and auto_selection_type
 *		XmAUTO_NO_CHANGE.
 *	XmEXTENDED_SELECT
 *		This action first performs the same processing as the ContainerButtonMotion()
 *		action, except that XmNselectionCallback is not called. If
 *		XmNautomaticSelection is XmNO_AUTO_SELECT, the XmNselectionCallback(s)
 *		is called with reason XmCR_EXTENDED_SELECT. If XmNautomaticSelection
 *		is XmAUTO_SELECT and a change in any item's selection state is made,
 *		XmNselectionCallback(s) is called with reason XmCR_EXTENDED_SELECT
 *		and auto_selection_type XmAUTO_CHANGE. If XmNautomaticSelection is
 *		XmAUTO_SELECT and this action makes no change in any item's selection
 *		state, XmNselectionCallback(s) is called with reason XmCR_EXTENDED_SELECT
 *		and auto_selection_type XmAUTO_NO_CHANGE.
 */
static void
ContainerEndSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	XmContainerSelectCallbackStruct	cbs;
	Widget				l[2];
	Boolean				changed = False;

	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerEndSelect", params, num_params));

#if 0
	/* FIX ME this comes not from documentation but it's a hack */
	ContainerActivate(w, event, params, num_params);
#endif
#if 1
	if (! _XmContainerToggleEvent(w, event)) {	/* FIX ME this is also a guess */
		return;
	}

	switch (ContainerSelectionPolicy(w)) {
	case XmSINGLE_SELECT:
	default:
		cbs.reason = XmCR_DEFAULT_ACTION;
		cbs.event = event;
		cbs.selected_items = l;	/* FIX ME */
		l[0] = ContainerIconHeader(w);
		l[1] = (Widget)0;
		if (l[0]) {
			cbs.selected_item_count = 1;	/* FIX ME */
		} else {
			cbs.selected_item_count = 0;	/* FIX ME */
		}
		cbs.auto_selection_type = 0;	/* FIX ME */

		XtCallCallbackList(w, ContainerSelectionCallback(w), (XtPointer)&cbs);
	/* ?? */
		ContainerIconHeader(w) = NULL;
		break;
	case XmBROWSE_SELECT:
		/* FIX ME */
	case XmMULTIPLE_SELECT:
	case XmEXTENDED_SELECT:
		changed = HandleContainerButtonMotion(False, w, event, params, num_params);
		break;
	}
#endif
}

static void
ContainerEndToggle(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerEndToggle", params, num_params));
}

static void
ContainerEndTransfer(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerEndTransfer", params, num_params));
}

static void
ContainerExpandOrCollapse(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerExpandOrCollapse", params, num_params));
}

static void
ContainerExtend(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerExtend", params, num_params));
}

static void
ContainerExtendCursor(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerExtendCursor", params, num_params));
}

static void
ContainerHandleBtn1Down(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerHandleBtn1Down", params, num_params));

	/* FIX ME - Do something depending on the state of XmNenableBtn1Transfer */

	/* If the pointer is over an unselected item or background, select it */

	/* Start transfer */

	/* FIX ME - somehow I think we must trigger this action */
	if (num_params) {
		XtCallActionProc(w, params[0], event, params + 1, (*num_params)-1);
	}
}

static void
ContainerHandleBtn1Motion(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerHandleBtn1Motion", params, num_params));
}

/*
 * 
 */
static void
ContainerHandleBtn1Up(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerHandleBtn1Up", params, num_params));

	if (0) {
		/* If a button 1 transfer is in progress, cancel it. */
		/* FIX ME */
	} else {
		/* Perform the action specified in the parameter */
		if (*num_params != 1) {
			_XmWarning(w, "ContainerHandleBtn1Up: #parameters should be 1");
			return;
		}

		XtCallActionProc(w, params[0], event, params, 0);
	}
}

static void
ContainerHandleBtn2Down(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerHandleBtn2Down", params, num_params));
}

static void
ContainerHandleBtn2Motion(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerHandleBtn2Motion", params, num_params));
}

static void
ContainerHandleBtn2Up(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerHandleBtn2Up", params, num_params));
}

static void
ContainerMoveCursor(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerMoveCursor", params, num_params));
}

static void
ContainerPrimaryCopy(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerPrimaryCopy", params, num_params));
}

static void
ContainerPrimaryLink(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerPrimaryLink", params, num_params));
}

static void
ContainerPrimaryMove(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerPrimaryMove", params, num_params));
}

static void
ContainerSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerSelect", params, num_params));
}

static void
ContainerSelectAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerSelectAll", params, num_params));
}

static void
ContainerStartTransfer(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerStartTransfer", params, num_params));
}

static void
ContainerToggleMode(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
	DEBUGOUT(_LtDebugAction(__FILE__, w, "ContainerToggleMode", params, num_params));
}
