/**
 *
 * $Id: RowColumn.c,v 1.73 1997/09/06 00:34:39 miers Exp $
 *
 * Copyright (C) 1996 Free Software Foundation, Inc.
 *
 * 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.
 *
 **/

static char rcsid[] = "$Id: RowColumn.c,v 1.73 1997/09/06 00:34:39 miers Exp $";

#include <LTconfig.h>
#include <XmI/XmI.h>

#include <X11/Xfuncs.h>
#include <Xm/XmP.h>
#include <Xm/BaseClassP.h>
#include <Xm/CascadeBP.h>
#include <Xm/CascadeBGP.h>
#include <Xm/DrawnBP.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/ManagerP.h>
#include <Xm/MenuShellP.h>
#include <Xm/MenuUtilP.h>
#include <Xm/PushBP.h>
#include <Xm/PushBGP.h>
#include <Xm/RepType.h>
#include <Xm/RowColumnP.h>
#include <Xm/RCUtilsP.h>
#include <Xm/ScreenP.h>
#include <Xm/Separator.h>
#include <Xm/SeparatoG.h>
#include <Xm/TearOffBP.h>
#include <Xm/ToggleBP.h>
#include <Xm/ToggleBGP.h>
#include <Xm/TransltnsP.h>

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>

#include <XmI/DebugUtil.h>

/*
 * builtin widgets for option menus
 */
#define RC_OPTION_LABEL		"OptionLabel"
#define RC_OPTION_CBG		"OptionButton"

/* Forward Declarations */

static void class_initialize();

static void class_part_initialize(WidgetClass w_class);

static void initialize(Widget request, Widget new_w, ArgList args,
		       Cardinal *num_args);

static void initialize_prehook(Widget request, Widget new_w, ArgList args,
			       Cardinal *num_args);

static void destroy(Widget w);

static void resize(Widget w);

static void realize(Widget w, XtValueMask *value_mask,
		    XSetWindowAttributes *attributes);

static void expose(Widget w, XEvent *event, Region region);

static XtGeometryResult query_geometry(Widget w, XtWidgetGeometry *proposed,
				       XtWidgetGeometry *answer);
static Boolean set_values(Widget current, Widget request, Widget new_w,
			  ArgList args, Cardinal *num_args);

static XtGeometryResult geometry_manager(Widget w, XtWidgetGeometry *request,
					 XtWidgetGeometry *reply);

static void change_managed(Widget w);

static void insert_child(Widget w);

static void delete_child(Widget w);

static void constraint_initialize(Widget request, Widget new,
				  ArgList args, Cardinal *num_args);

static Boolean constraint_set_values(Widget current, Widget request, Widget new,
				     ArgList args, Cardinal *num_args);

static XmNavigability widget_navigable(Widget w);

static void MenuProcEntry(int proc, Widget rc,...);

static void ArmAndActivate(Widget w, XEvent *e, String *args, Cardinal *nargs);

static void _XmOptionCallback(Widget w, XtPointer cd, XtPointer cbs);

void _XmRadioCallback(Widget w, XtPointer cd, XtPointer cbs);

static void _XmEntryCallback(Widget w, XtPointer cd, XtPointer cbs);

static void _XmFromMenuPost(Widget widget, int offset, XtArgVal *value);

static XmImportOperator _XmToMenuPost(Widget widget, int offset,
				      XtArgVal *value);

static Cardinal _XmRowColumnOrderProc(Widget widget);

static void _XmRowColumnEntryClassDefault(Widget w,
					  int offset,
					  XrmValue *val);

static void _XmRowColumnIsHomogeneousDefault(Widget w,
					     int offset,
					     XrmValue *val);

static void _XmRowColumnMenuAcceleratorDefault(Widget w,
					       int offset,
					       XrmValue *val);


extern void _XmRCPreferredSize(Widget w, XtWidgetGeometry *rcg);

extern XtGeometryResult _XmRCAdjustSize(Widget w, Widget instig,
					XtWidgetGeometry *ireq);

extern void _XmRCSetMargins(Widget w);

extern void _XmFixOptionMenu(Widget new_w, Boolean use_set_values);

/*
 * offset macros
 */
#define Offset(field) XtOffsetOf(XmRowColumnRec, row_column.field)
#define MGR_Offset(field) XtOffsetOf(XmRowColumnRec, manager.field)
#define COMP_Offset(field) XtOffsetOf(XmRowColumnRec, composite.field)

/* Resources for the RowColumn class */
static XtResource resources[] =
{
    {
	XmNresizeWidth, XmCResizeWidth, XmRBoolean,
	sizeof(Boolean), Offset(resize_width),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNresizeHeight, XmCResizeHeight, XmRBoolean,
	sizeof(Boolean), Offset(resize_height),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNwhichButton, XmCWhichButton, XmRWhichButton,
	sizeof(unsigned int), Offset(postButton),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
	/* add support for this!!! */
    },
    {
	XmNmenuPost, XmCMenuPost, XmRString,
	sizeof(String), Offset(menuPost),
	XmRString, (XtPointer)NULL
    },
    {
	XmNadjustLast, XmCAdjustLast, XmRBoolean,
	sizeof(Boolean), Offset(adjust_last),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
	sizeof(Dimension), Offset(margin_width),
	XmRImmediate, (XtPointer)XmINVALID_DIMENSION
    },
    {
	XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
	sizeof(Dimension), Offset(margin_height),
	XmRImmediate, (XtPointer)XmINVALID_DIMENSION
    },
    {
	XmNentryCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(entry_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNmapCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(map_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNunmapCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(unmap_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNorientation, XmCOrientation, XmROrientation,
	sizeof(unsigned char), Offset(orientation),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
	/*FIX ME: Should be XmROrientation, (XtPointer)some whacko thing here */
    },
    {
	XmNspacing, XmCSpacing, XmRHorizontalDimension,
	sizeof(Dimension), Offset(spacing),
	XmRImmediate, (XtPointer)XmINVALID_DIMENSION
    },
    {
	XmNentryBorder, XmCEntryBorder, XmRHorizontalDimension,
	sizeof(Dimension), Offset(entry_border),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNisAligned, XmCIsAligned, XmRBoolean,
	sizeof(Boolean), Offset(do_alignment),
	XmRImmediate, (XtPointer)True
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNentryAlignment, XmCAlignment, XmRAlignment,
	sizeof(unsigned char), Offset(entry_alignment),
	XtRImmediate, (XtPointer)XmALIGNMENT_BEGINNING
	/* FIX ME: Motif has XmRAlignment, (XtPointer)whacko value */
    },
    {
	XmNadjustMargin, XmCAdjustMargin, XmRBoolean,
	sizeof(Boolean), Offset(adjust_margin),
	XtRImmediate, (XtPointer)True
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNnumColumns, XmCNumColumns, XmRShort,
	sizeof(short), Offset(num_columns),
	XtRImmediate, (XtPointer)1
	/* FIX ME: Motif has XmRShort, (XtPointer)whacko value */
    },
    {
	XmNradioBehavior, XmCRadioBehavior, XmRBoolean,
	sizeof(Boolean), Offset(radio),
	XmRImmediate, (XtPointer)False
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNradioAlwaysOne, XmCRadioAlwaysOne, XmRBoolean,
	sizeof(Boolean), Offset(radio_one),
	XmRImmediate, (XtPointer)True
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNisHomogeneous, XmCIsHomogeneous, XmRBoolean,
	sizeof(Boolean), Offset(homogeneous),
	XtRCallProc, (XtPointer)_XmRowColumnIsHomogeneousDefault
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNentryClass, XmCEntryClass, XmRWidgetClass,
	sizeof(WidgetClass), Offset(entry_class),
	XmRCallProc, (XtPointer)_XmRowColumnEntryClassDefault
	/* Motif has XmRWidgetClass, (XtPointer)NULL */
    },
    {
	XmNrowColumnType, XmCRowColumnType, XmRRowColumnType,
	sizeof(unsigned char), Offset(type),
	XtRImmediate, (XtPointer)XmWORK_AREA
	/* FIX ME: Motif has XmRRowColumnType, (XtPointer)whacko value */
    },
    {
	XmNmenuHelpWidget, XmCMenuWidget, XmRMenuWidget,
	sizeof(Widget), Offset(help_pushbutton),
	XmRImmediate, (XtPointer)NULL
	/* FIX ME: Motif has XmRMenuWidget, (XtPointer)whacko value */
    },
    {
	XmNlabelString, XmCXmString, XmRXmString,
	sizeof(XmString), Offset(option_label),
	XmRXmString, (XtPointer)NULL
    },
    {
	XmNsubMenuId, XmCMenuWidget, XmRMenuWidget,
	sizeof(Widget), Offset(option_submenu),
	XmRImmediate, (XtPointer)NULL
	/* FIX ME: Motif has XmRMenuWidget, (XtPointer)whacko value */
    },
    {
	XmNmenuHistory, XmCMenuWidget, XmRMenuWidget,
	sizeof(Widget), Offset(memory_subwidget),
	XmRImmediate, (XtPointer)NULL
	/* FIX ME: Motif has XmRMenuWidget, (XtPointer)whacko value */
    },
    {
	XmNpopupEnabled, XmCPopupEnabled, XmRBoolean,
	sizeof(Boolean), Offset(popup_enabled),
	XmRImmediate, (XtPointer)True
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNmenuAccelerator, XmCAccelerators, XmRString,
	sizeof(String), Offset(menu_accelerator),
	XtRCallProc, (XtPointer)_XmRowColumnMenuAcceleratorDefault
	/* FIX ME: Motif has XmRString, (XtPointer)whacko values */
    },
    {
	XmNmnemonic, XmCMnemonic, XmRKeySym,
	sizeof(KeySym), Offset(mnemonic),
	XmRImmediate, (XtPointer)NULL
    },
    {
	XmNmnemonicCharSet, XmCMnemonicCharSet, XmRString,
	sizeof(String), Offset(mnemonicCharSet),
	XtRImmediate, (XtPointer)XmFONTLIST_DEFAULT_TAG
    },
    {
	XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
	sizeof(Dimension), MGR_Offset(shadow_thickness),
	XmRImmediate, (XtPointer)XmINVALID_DIMENSION
    },
    {
	XmNpostFromList, XmCPostFromList, XmRWidgetList,
	sizeof(WidgetList), Offset(postFromList),
	XmRWidgetList, (XtPointer)NULL
    },
    {
	XmNpostFromCount, XmCPostFromCount, XmRInt,
	sizeof(int), Offset(postFromCount),
	XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
    {
	XmNnavigationType, XmCNavigationType, XmRNavigationType,
	sizeof(XmNavigationType), MGR_Offset(navigation_type),
	XmRImmediate, (XtPointer)((XmNavigationType)XmUNSPECIFIED)
    },
    {
	XmNentryVerticalAlignment, XmCVerticalAlignment, XmRVerticalAlignment,
	sizeof(unsigned char), Offset(entry_vertical_alignment),
	XtRImmediate, (XtPointer)XmALIGNMENT_BEGINNING
	/* FIX ME: Motif has XmRVerticalAlignment, (XtPointer)whacko values */
    },
    {
	XmNtearOffModel, XmCTearOffModel, XmRTearOffModel,
	sizeof(unsigned char), Offset(TearOffModel),
	XtRImmediate, (XtPointer)XmTEAR_OFF_DISABLED
	/* FIX ME: Motif has XmRTearOffModel, (XtPointer)whacko values */
    },
    {
	XmNtearOffMenuActivateCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(tear_off_activated_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNtearOffMenuDeactivateCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(tear_off_deactivated_callback),
	XmRCallback, (XtPointer)NULL
    },
    {
	XmNinsertPosition, XmCInsertPosition, XmRFunction,
	sizeof(XtOrderProc), COMP_Offset(insert_position),
	XmRImmediate, (XtPointer)_XmRowColumnOrderProc,
    },
    {
	XmNpacking, XmCPacking, XmRPacking,
	sizeof(unsigned char), Offset(packing),
	XmRImmediate, (XtPointer)XmUNSPECIFIED	/* To be overruled in initialize */
    }
};

static XmSyntheticResource syn_resources[] =
{
    {
	XmNmnemonicCharSet,
	sizeof(String), Offset(mnemonicCharSet),
	NULL /* FIX ME */ , NULL
    },
    {
	XmNmenuAccelerator,
	sizeof(String), Offset(menu_accelerator),
	NULL /* FIX ME */ , NULL
    },
    {
	XmNmenuPost,
	sizeof(String), Offset(menuPost),
	_XmFromMenuPost, _XmToMenuPost,
    },
    {
	XmNlabelString,
	sizeof(XmString), Offset(option_label),
	NULL /* FIX ME */ , NULL
    },
    {
	XmNspacing,
	sizeof(Dimension), Offset(spacing),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    {
	XmNmarginHeight,
	sizeof(Dimension), Offset(margin_height),
	_XmFromVerticalPixels, _XmToVerticalPixels
    },
    {
	XmNmarginWidth,
	sizeof(Dimension), Offset(margin_width),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    {
	XmNentryBorder,
	sizeof(Dimension), Offset(entry_border),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    }
};

#undef Offset

#define Offset(field) XtOffsetOf(XmRowColumnConstraintRec, row_column.field)
static XtResource rowColumnConstraintResources[] =
{
    {
	XmNpositionIndex, XmCPositionIndex, XmRShort,
	sizeof(short), Offset(position_index),
	XmRImmediate, (XtPointer)XmLAST_POSITION
    }
};

/* not all actually written yet... */
#define STATIC_ACTION(fn) static void (fn)(Widget, XEvent*, String*, Cardinal*)
#define ACTION(fn) void (fn)(Widget, XEvent*, String*, Cardinal*)

STATIC_ACTION(MenuBarEnter);
STATIC_ACTION(MenuBarLeave);
STATIC_ACTION(MenuBarGadgetSelect);
STATIC_ACTION(MenuBtnDown);
STATIC_ACTION(MenuBtnUp);
ACTION(_XmMenuHelp);
STATIC_ACTION(MenuEnter);
STATIC_ACTION(MenuUnmap);
STATIC_ACTION(MenuFocusIn);
STATIC_ACTION(MenuFocusOut);
STATIC_ACTION(DoBtnEventCleanupReplay);

static Boolean ExternalBtnEvent(Widget w, XEvent *event);
#undef STATIC_ACTION
#undef ACTION

static XtActionsRec actions[] =
{
    {"MenuBarEnter", MenuBarEnter},
    {"MenuBarLeave", MenuBarLeave},
    {"MenuBarGadgetSelect", MenuBarGadgetSelect},
    {"MenuBtnDown", MenuBtnDown},
    {"MenuBtnUp", MenuBtnUp},
    {"MenuFocusIn", MenuFocusIn},
    {"MenuFocusOut", MenuFocusOut},
    {"MenuHelp", _XmMenuHelp},
    {"MenuUnmap", MenuUnmap},
    {"MenuEnter", MenuEnter},
    {"MenuGadgetEscape", _XmMenuEscape},
    {"MenuGadgetTraverseLeft", _XmMenuTraverseLeft},
    {"MenuGadgetTraverseRight", _XmMenuTraverseRight},
    {"MenuGadgetTraverseUp", _XmMenuTraverseUp},
    {"MenuGadgetTraverseDown", _XmMenuTraverseDown},
};

/* *INDENT-OFF* */
static XmBaseClassExtRec _XmRowColumnCoreClassExtRec =
{
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,
    /* version                   */ XmBaseClassExtVersion,
    /* size                      */ sizeof(XmBaseClassExtRec),
    /* initialize_prehook        */ initialize_prehook,
    /* set_values_prehook        */ NULL,
    /* initialize_posthook       */ NULL,
    /* set_values_posthook       */ NULL,
    /* secondary_object_class    */ NULL,
    /* secondary_object_create   */ NULL,
    /* get_secondary_resources   */ NULL,
    /* fast_subclass             */ {0},
    /* get_values_prehook        */ NULL,
    /* get_values_posthook       */ NULL,
    /* class_part_init_prehook   */ NULL,
    /* class_part_init_posthook  */ NULL,
    /* ext_resources             */ NULL,
    /* compiled_ext_resources    */ NULL,
    /* num_ext_resources         */ 0,
    /* use_sub_resources         */ False,
    /* widget_navigable          */ widget_navigable,
    /* focus_change              */ 0,/**********XmInheritFocusChange,*/
    /* wrapper_data              */ NULL
};

static CompositeClassExtensionRec rcCompositeExt =
{
    /* next_extension */ NULL,
    /* record_type    */ NULLQUARK,
    /* version        */ XtCompositeExtensionVersion,
    /* record_size    */ sizeof(CompositeClassExtensionRec),
    /* accepts_objects */ True,
#if XtSpecificationRelease >= 6
    /* allows_change_managed_set */ True
#endif
};

static XmManagerClassExtRec _XmRowColumnMClassExtRec =
{
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,
    /* version                   */ XmManagerClassExtVersion,
    /* record_size               */ sizeof(XmManagerClassExtRec),
    /* traversal_children        */ NULL /* FIX ME */
};

XmRowColumnClassRec xmRowColumnClassRec =
{
    /* Core class part */
    {
	/* superclass            */ (WidgetClass) & xmManagerClassRec,
	/* class_name            */ "XmRowColumn",
	/* widget_size           */ sizeof(XmRowColumnRec),
	/* class_initialize      */ class_initialize,
	/* class_part_initialize */ class_part_initialize,
	/* class_inited          */ False,
	/* initialize            */ initialize,
	/* initialize_hook       */ NULL,
	/* realize               */ realize,
	/* actions               */ actions,
	/* num_actions           */ XtNumber(actions),
	/* resources             */ resources,
	/* num_resources         */ XtNumber(resources),
	/* xrm_class             */ NULLQUARK,
	/* compress_motion       */ True,
	/* compress_exposure     */ XtExposeCompressMultiple,
	/* compress_enterleave   */ True,
	/* visible_interest      */ True,
	/* destroy               */ destroy,
	/* resize                */ resize,
	/* expose                */ expose,
	/* set_values            */ set_values,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ 0,/*********XtInheritSetValuesAlmost,*/
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ 0,/*********XtInheritTranslations,*/
	/* query_geometry        */ query_geometry,
	/* display_accelerator   */ 0,/*********XtInheritDisplayAccelerator,*/
	/* extension             */ (XtPointer) &_XmRowColumnCoreClassExtRec
    },
    /* Composite class part */
    {
	/* geometry manager */	geometry_manager,
	/* change_managed   */	change_managed,
	/* insert_child     */	insert_child,
	/* delete_child     */	delete_child,
	/* extension        */	(XtPointer) &rcCompositeExt,
    },
    /* Constraint class part */
    {
	/* subresources      */ rowColumnConstraintResources,
	/* subresource_count */ XtNumber(rowColumnConstraintResources),
	/* constraint_size   */ sizeof(XmRowColumnConstraintRec),
	/* initialize        */ constraint_initialize,
	/* destroy           */ NULL,
	/* set_values        */ constraint_set_values,
	/* extension         */ NULL,
    },
    /* XmManager class part */
    {
	/* translations           */ 0,/*********XmInheritTranslations,*/
	/* syn_resources          */ syn_resources,
	/* num_syn_resources      */ XtNumber(syn_resources),
	/* syn_constraint_res     */ NULL,
	/* num_syn_constraint_res */ 0,
	/* parent_process         */ 0,/********XmInheritParentProcess,*/
	/* extension              */ (XtPointer)&_XmRowColumnMClassExtRec
    },
    /* XmRowColumn Area part */
    {
	/* menuProcedures   */ MenuProcEntry,
	/* armAndActivate   */ ArmAndActivate,
	/* traversalHandler */ _XmMenuTraversalHandler,
	/* extension        */ NULL,
    },
};
/* *INDENT-ON* */


int AMIWIN_RowColumn(void)
{
_XmRowColumnCoreClassExtRec.focusChange=XmInheritFocusChange;

xmRowColumnClassRec.translations=XmInheritTranslations;
xmRowColumnClassRec.parent_process=XmInheritParentProcess;
xmRowColumnClassRec.set_values_almost=XtInheritSetValuesAlmost;
xmRowColumnClassRec.tm_table=AMIWIN_XtInheritTranslations;
xmRowColumnClassRec.display_accelerator=XtInheritDisplayAccelerator;
return(0);
}


WidgetClass xmRowColumnWidgetClass = (WidgetClass)&xmRowColumnClassRec;

static void
class_initialize()
{
    _XmRowColumnCoreClassExtRec.record_type = XmQmotif;
}

static void
class_part_initialize(WidgetClass widget_class)
{
    CompositeClassExtension ext, *extptr;
    XmRowColumnWidgetClass rc_class = (XmRowColumnWidgetClass)widget_class;

    extptr = (CompositeClassExtension *)
	_XmGetClassExtensionPtr((XmGenericClassExt *)
				&(rc_class->composite_class.extension),
				NULLQUARK);

    if (extptr == NULL || *extptr == NULL)
    {
	ext = (CompositeClassExtension)XtNew(CompositeClassExtensionRec);
	if (ext != NULL)
	{
	    ext->next_extension = rc_class->composite_class.extension;
	    ext->record_type = NULLQUARK;
	    ext->version = XtCompositeExtensionVersion;
	    ext->record_size = sizeof(CompositeClassExtensionRec);
	    ext->accepts_objects = True;
#if XtSpecificationRelease >= 6
	    ext->allows_change_managed_set = True;
#endif
	    rc_class->composite_class.extension = (XtPointer)ext;
	}
    }

    _XmFastSubclassInit(widget_class, XmROW_COLUMN_BIT);
}

static void
_XmRcCreateTearOffControl(Widget rc)
{
    RC_TearOffControl(rc) = XtVaCreateManagedWidget("TearOffControl",
						xmTearOffButtonWidgetClass, rc,
						    XmNpositionIndex, 0,
						    NULL);
}

static void
_XmRcDestroyTearOffControl(Widget rc)
{
    if (RC_TearOffControl(rc))
    {
	XtDestroyWidget(RC_TearOffControl(rc));
    }
    RC_TearOffControl(rc) = NULL;
}

static void
initialize_prehook(Widget request, Widget new_w,
		   ArgList args, Cardinal *num_args)
{
    if (RC_Type(new_w) == XmWORK_AREA || RC_Type(new_w) == XmMENU_OPTION)
    {
	MGR_NavigationType(new_w) = XmTAB_GROUP;
    }
    else
    {
	MGR_NavigationType(new_w) = XmNONE;
    }

    MGR_TraversalOn(new_w) = True;
}

static void
initialize(Widget request, Widget new_w,
	   ArgList args, Cardinal *num_args)
{
    RC_Boxes(new_w) = NULL;	/* no initial children */

    /* FIX ME: Check if parent is MenuShell if pulldown or option menu */
    if (RC_Type(new_w) == XmMENU_OPTION)
    {
	MGR_ShadowThickness(new_w) = 0;
    }
    else
    {
	if (MGR_ShadowThickness(new_w) == XmINVALID_DIMENSION)
	{
	    if (RC_Type(new_w) == XmMENU_PULLDOWN ||
		RC_Type(new_w) == XmMENU_POPUP ||
		RC_Type(new_w) == XmMENU_BAR)
	    {
		MGR_ShadowThickness(new_w) = 2;
	    }
	    else
	    {
		MGR_ShadowThickness(new_w) = 0;
	    }
	}
    }

    /* now, we install our translations, 
     * depending on the row column type */

    if (RC_Type(new_w) != XmWORK_AREA)
    {
	XtOverrideTranslations(new_w,
			     XtParseTranslationTable(_XmRowColumn_menu_table));
	XtOverrideTranslations(new_w,
		   XtParseTranslationTable(_XmRowColumn_menu_traversal_table));
    }

    ((XmRowColumnWidget)new_w)->row_column.armed = 0;	/* FIX ME: macro */

    if (RC_Spacing(new_w) == XmINVALID_DIMENSION)
    {
	if (RC_Type(new_w) == XmMENU_OPTION || RC_Type(new_w) == XmWORK_AREA)
	{
	    RC_Spacing(new_w) = 3;
	}
	else
	{
	    RC_Spacing(new_w) = 0;
	}
    }

    if (RC_MarginW(new_w) == XmINVALID_DIMENSION)
    {
	if (RC_Type(new_w) == XmMENU_POPUP || RC_Type(new_w) == XmMENU_PULLDOWN)
	{
	    RC_MarginW(new_w) = 0;
	}
	else
	{
	    RC_MarginW(new_w) = 3;
	}
    }
    if (RC_MarginH(new_w) == XmINVALID_DIMENSION)
    {
	if (RC_Type(new_w) == XmMENU_POPUP || RC_Type(new_w) == XmMENU_PULLDOWN)
	{
	    RC_MarginH(new_w) = 0;
	}
	else
	{
	    RC_MarginH(new_w) = 3;
	}
    }

    RC_LastSelectToplevel(new_w) = NULL;

    if (RC_Type(new_w) == XmMENU_OPTION)
    {
	XtOverrideTranslations(new_w,
			   XtParseTranslationTable(_XmRowColumn_option_table));

	RC_LastSelectToplevel(new_w) = new_w;

    }
    else if (RC_Type(new_w) == XmMENU_BAR)
    {
	XtOverrideTranslations(new_w,
			       XtParseTranslationTable(_XmRowColumn_bar_table));

	RC_LastSelectToplevel(new_w) = new_w;

    }

    /* Internal widgets */

    RC_CascadeBtn(new_w) = NULL;
    RC_PopupPosted(new_w) = NULL;

    /* Tear off stuff */
    RC_SetTornOff(new_w, 0);
    RC_SetFromInit(new_w, 0);
    RC_SetTearOffDirty(new_w, 0);
    RC_SetTearOffActive(new_w, 0);
    RC_ParentShell(new_w) = NULL;
    RC_TearOffControl(new_w) = NULL;

    if (RC_Type(new_w) == XmMENU_OPTION)
    {
	Widget cb;

	if (RC_OptionLabel(new_w))
	{
	    XtVaCreateManagedWidget(RC_OPTION_LABEL,
				    xmLabelGadgetClass,
				    new_w,
				    XmNlabelString, RC_OptionLabel(new_w),
				    XmNmarginTop, 0,
				    XmNmarginBottom, 0,
				    NULL);
	}
	else
	{
	    XtVaCreateWidget(RC_OPTION_LABEL,
			     xmLabelGadgetClass,
			     new_w,
			     XmNlabelString, RC_OptionLabel(new_w),
			     NULL);
	}
	cb = XtVaCreateManagedWidget(RC_OPTION_CBG,
				     xmCascadeButtonGadgetClass,
				     new_w,
				     XmNsubMenuId, RC_OptionSubMenu(new_w),
				     NULL);

	RC_DoMarginAdjust(new_w) = False; /* This is to get test28 correct */
	_XmFixOptionMenu(new_w, True);

	/* If we have XmNmenuHistory, copy it */
	if (RC_MemWidget(new_w))
	{
	    XmString xms = NULL;
	    Arg a;
	    XtSetArg(a, XmNlabelString, &xms);
	    XtGetValues(RC_MemWidget(new_w), &a, 1);
	    XtSetArg(a, XmNlabelString, xms);
	    XtSetValues(cb, &a, 1);
	    XmStringFree(xms);
	}
    }

    /* just to initialize it. */
    RC_SetFromResize(new_w, 0);

    /* menuPost stuff. */
    if (RC_MenuPost(new_w) == NULL)
    {
	if (RC_Type(new_w) == XmMENU_OPTION
	    || RC_Type(new_w) == XmWORK_AREA
	    || RC_Type(new_w) == XmMENU_BAR)
	{
	    RC_MenuPost(new_w) = "<Button1Down>";
	}
    }

    if (RC_Packing(new_w) == (unsigned char)XmUNSPECIFIED)
    {
	/*
	 * This is what the XmRowColumn manual page says
	 *      (end of the text describing XmNpacking).
	 */
	if (RC_RadioBehavior(new_w) && RC_Type(new_w) == XmWORK_AREA)
	{
	    RC_Packing(new_w) = XmPACK_COLUMN;
	}
	else if (RC_Type(new_w) == XmMENU_OPTION)
	{
	    RC_Packing(new_w) = XmPACK_TIGHT;
	}
	else
	{
	    RC_Packing(new_w) = XmPACK_TIGHT;
	}
    }

    if (RC_Orientation(new_w) == (unsigned char)XmUNSPECIFIED)
    {
	if (RC_Type(new_w) == XmMENU_PULLDOWN ||
	    RC_Type(new_w) == XmMENU_POPUP)
	{
	    RC_Orientation(new_w) = XmVERTICAL;
	}
	else if (RC_Type(new_w) == XmMENU_OPTION ||
		 RC_Type(new_w) == XmMENU_BAR)
	{
	    RC_Orientation(new_w) = XmHORIZONTAL;
	}
	else
	{
	    RC_Orientation(new_w) = XmVERTICAL;
	}
    }

    /* Be verbose about it ... */
    if (XdbInDebug(__FILE__, new_w))
    {
	DEBUGOUT(XdbDebug(__FILE__,
			  new_w,
		    "Initialize: RadioBehavior %s, RC_Type %s => Packing %s\n",
			  XdbBoolean2String(RC_RadioBehavior(new_w)),
			  XdbRcType2String(RC_Type(new_w)),
			  XdbPacking2String(RC_Packing(new_w))));
    }

    /* Initialize sizes if not already done */
    if (RC_Type(new_w) == XmMENU_BAR)
    {
#if 0
	if (XtWidth(new_w) == 0)
	{
	    XtWidth(new_w) = 1;	/* FIX ME */
	}
	if (XtHeight(new_w) == 0)
	{
	    XtHeight(new_w) = 20;	/* FIX ME */
	}
#endif
    }
#if 0
    /* FIX ME: This should be enabled as soon as MGR_HighlightedWidget(w) =
     * NULL is moved from MenuUnmap to Manager's event handler.
     */
    else if (RC_Type(new_w) == XmMENU_PULLDOWN)
    {
	new_w->core.mapped_when_managed = False;
    }
#endif
}

static void
destroy(Widget w)
{
    if (RC_Boxes(w))
    {
	XtFree((XtPointer)RC_Boxes(w));
    }
}

Widget
XmOptionButtonGadget(Widget option_menu)
{
    return XtNameToWidget(option_menu, RC_OPTION_CBG);
}

Widget
XmOptionLabelGadget(Widget option_menu)
{
    return XtNameToWidget(option_menu, RC_OPTION_LABEL);
}

static Boolean
set_values(Widget old, Widget request, Widget new_w,
	   ArgList args, Cardinal *num_args)
{
    Boolean need_refresh = False, need_relayout = False;

    DEBUGOUT(XdbDebug(__FILE__, new_w, "RowColumn set_values()\n"));

    if (RC_EntryAlignment(old) != RC_EntryAlignment(new_w))
    {
	int i;
	Arg a;

	XtSetArg(a, XmNalignment, RC_EntryAlignment(new_w));
	DEBUGOUT(XdbDebug(__FILE__, new_w,
			  "Setting Alignment for children to %s\n",
			  XdbAlignment2String(RC_EntryAlignment(new_w))));

	for (i = 0; i < MGR_NumChildren(new_w); i++)
	{
	    if (XmIsLabel(MGR_Children(new_w)[i])
		|| XmIsLabelGadget(MGR_Children(new_w)[i]))
	    {
		DEBUGOUT(XdbDebug2(__FILE__, new_w, MGR_Children(new_w)[i],
				   "Set Alignment to %s\n",
			       XdbAlignment2String(RC_EntryAlignment(new_w))));
		XtSetValues(MGR_Children(new_w)[i], &a, 1);
	    }
	}
    }

    if ((RC_Orientation(old) != RC_Orientation(new_w)) ||
	(RC_Packing(old) != RC_Packing(new_w)))
    {
	need_relayout = True;
	need_refresh = True;
    }

    if ((RC_TearOffModel(new_w) != RC_TearOffModel(old)) &&
	(RC_Type(new_w) == XmMENU_POPUP || RC_Type(new_w) == XmMENU_PULLDOWN))
    {
	if (RC_TearOffModel(new_w) == XmTEAR_OFF_ENABLED)
	{
	    _XmRcCreateTearOffControl(new_w);
	}
	else
	{
	    _XmRcDestroyTearOffControl(new_w);
	}

	need_relayout = True;
    }

    if (RC_Type(new_w) == XmMENU_OPTION
	&& RC_OptionSubMenu(new_w) != RC_OptionSubMenu(old))
    {
	int i;

	/* Oh yes this is very efficient :-( */
	for (i = 0; i < MGR_NumChildren(new_w); i++)
	{
	    if (XtIsSubclass(MGR_Children(new_w)[i],
			     xmCascadeButtonGadgetClass))
	    {
		XtVaSetValues(MGR_Children(new_w)[i],
			      XmNsubMenuId,
			      RC_OptionSubMenu(new_w),
			      NULL);

		DEBUGOUT(XdbDebug2(__FILE__,
				   new_w,
				   MGR_Children(new_w)[i],
				   "Assign SubMenuId (%s)\n",
				   XtName(RC_OptionSubMenu(new_w))));
		break;
	    }
	}

	_XmFixOptionMenu(new_w, True);
    }

    /* rws take care of setValues on menuHistory */
    if (RC_Type(new_w) == XmMENU_OPTION
	&& (RC_MemWidget(new_w) != RC_MemWidget(old)))
    {
	_XmOptionCallback(RC_MemWidget(new_w), (XtPointer)new_w, NULL);
    }

    if (need_relayout)
    {
	DEBUGOUT(XdbDebug(__FILE__, new_w,
			  "_XmRCAdjustSize from set_values\n"));
	_XmRCAdjustSize(new_w, NULL, NULL);
    }

    return need_refresh;
}

static void
realize(Widget w, XtValueMask *value_mask, XSetWindowAttributes *attributes)
{
    /* FIX ME: test whether parent is a menushell? */
    /* FIX ME: grab bit should be set for the pane, not for the option menu
     * itself.
     */
    if (RC_Type(w) == XmMENU_OPTION)
    {
	*value_mask |= CWEventMask;
	attributes->event_mask |= OwnerGrabButtonMask;
    }

#define superclass (&xmManagerClassRec)
    (*superclass->core_class.realize) (w, value_mask, attributes);
#undef superclass
}

static void
resize(Widget w)
{
    RC_SetFromResize(w, 1);

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmRCAdjustSize from resize\n"));

    _XmRCAdjustSize(w, NULL, NULL);

    RC_SetFromResize(w, 0);
}

static void
expose(Widget w, XEvent *event, Region region)
{

    if (RC_Type(w) != XmWORK_AREA)
    {
	_XmDrawShadows(XtDisplay(w),
		       XtWindow(w),
		       MGR_TopShadowGC(w),
		       MGR_BottomShadowGC(w),
		       0, 0,
		       XtWidth(w),
		       XtHeight(w),
		       MGR_ShadowThickness(w),
		       XmSHADOW_OUT);
    }

    /* display the gadgets, if there are any */
    _XmRedisplayGadgets(w, event, region);
}

static XtGeometryResult
query_geometry(Widget w,
	       XtWidgetGeometry *request,
	       XtWidgetGeometry *reply)
{
    XtGeometryResult result = XtGeometryYes;
    Dimension width, height, border_width;
    XtWidgetGeometry rcg;

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "RC QueryGeometry, request %s\n",
		      XdbWidgetGeometry2String(request)));

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "_XmRCPreferredSize from query_geometry\n"));

    _XmRCPreferredSize(w, &rcg);

    width = (rcg.request_mode & CWWidth) ? rcg.width : XtWidth(w);
    height = (rcg.request_mode & CWHeight) ? rcg.height : XtHeight(w);
    border_width = (rcg.request_mode & CWBorderWidth)
	? rcg.border_width
	: XtBorderWidth(w);

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "preferred size %s\n", XdbWidgetGeometry2String(&rcg)));

    reply->width = width;
    reply->height = height;
    reply->border_width = border_width;

    /* Not interested in more flags */
    request->request_mode &= CWWidth | CWHeight | CWBorderWidth;

    if (request->request_mode == 0)
    {
	reply->request_mode = CWWidth | CWHeight | CWBorderWidth;

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "RC QueryGeometry(NULL) => XtGeometryYes, %d %d %d\n",
			  width, height, border_width));
	return result;
    }

    if (request->request_mode & CWWidth)
    {
	if (request->width < width)
	{
	    result = XtGeometryAlmost;
	    reply->width = width;
	    reply->request_mode |= CWWidth;
	}
    }
    if (request->request_mode & CWHeight)
    {
	if (request->height < height)
	{
	    result = XtGeometryAlmost;
	    reply->height = height;
	    reply->request_mode |= CWHeight;
	}
    }
    if (request->request_mode & CWBorderWidth)
    {
	if (request->border_width < border_width)
	{
	    result = XtGeometryAlmost;
	    reply->border_width = border_width;
	    reply->request_mode |= CWBorderWidth;
	}
    }

    reply->width = width;
    reply->height = height;
    reply->border_width = border_width;
    reply->request_mode = CWWidth | CWHeight | CWBorderWidth;

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "RC QueryGeometry() => %s, %d %d %d\n",
		      XdbGeometryResult2String(result), width, height,
		      border_width));

    return result;
}

/*
 * Every time we return XtGeometryYes, we have a situation where a
 *  child widget is granted permission to change its geometry. We'll have to
 *  assume that it does this, and change our "boxes".
 * An alternative would be to indicate in boxes that its contents is invalid,
 *  and have the next user of boxes look up the new geometry info.
 * Partially applied 25/8/1996 (Danny).
 */
static XtGeometryResult
geometry_manager(Widget w,
		 XtWidgetGeometry *request,
		 XtWidgetGeometry *reply)
{
    Widget rc = XtParent(w);
    XtWidgetGeometry wants;
    int ask, got;

    wants = *request;
    *reply = wants;

    DEBUGOUT(XdbDebug2(__FILE__, rc, w,
		       "RC geometry_manager: _XmRCAdjustSize\n"));
    DEBUGOUT(XdbDebug(__FILE__, rc,
		      "Is currently %d %d.\n", XtWidth(rc), XtHeight(rc)));

    if (_XmRCAdjustSize(rc, w, reply) == XtGeometryNo)
    {
	DEBUGOUT(XdbDebug(__FILE__, rc, "Parent said no. So will we.\n"));

	return XtGeometryNo;
    }

    DEBUGOUT(XdbDebug(__FILE__, rc,
		      "RC geometry_manager after _XmRCAdjustSize\n"));
    DEBUGOUT(XdbDebug(__FILE__, rc,
		      "Now at %d %d.\n", XtWidth(rc), XtHeight(rc)));

    reply->request_mode &= wants.request_mode;

    ask = got = 0;

    if ((wants.request_mode & CWWidth) == CWWidth)
    {
	ask++;

	if (reply->width == wants.width)
	{
	    got++;
	}
    }
    if ((wants.request_mode & CWHeight) == CWHeight)
    {
	ask++;

	if (reply->width == wants.width)
	{
	    got++;
	}
    }
    if ((wants.request_mode & CWBorderWidth) == CWBorderWidth)
    {
	ask++;

	if (reply->border_width == wants.border_width)
	{
	    got++;
	}
    }

    /*
     * the next two are a little tricky.  If the child asked for x/y
     * and the packing type isn't NONE, they don't get it.
     */
    if ((wants.request_mode & CWX) == CWX)
    {
	ask++;

	if (RC_Packing(rc) == XmPACK_NONE && reply->x == wants.x)
	{
	    got++;
	}
    }
    if ((wants.request_mode & CWY) == CWY)
    {
	ask++;

	if (RC_Packing(rc) == XmPACK_NONE && reply->y == wants.y)
	{
	    got++;
	}
    }

    /* are we ok with everything they want. */
    if (ask == got && ask != 0)
    {
	DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			   "geometry_manager request [%s] reply [%s] => YES\n",
			   XdbWidgetGeometry2String(&wants),
			   XdbWidgetGeometry2String(reply)));

	_XmRCSetMargins(rc);
	_XmRCSetKidGeo(RC_Boxes(rc), w);

	return XtGeometryYes;
    }
    /* no, but we can always compromise. LayoutNone is mostly handled if
     * we got No when we made the geometry request. Otherwise the layout
     * routine computed a compromise, which is typically the size they
     * are before they made this request. */
    else
    {
	if (RC_Packing(rc) != XmPACK_NONE)
	{
	    reply->request_mode &= ~(CWX | CWY);
	}

	DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			"geometry_manager request [%s] reply [%s] => ALMOST\n",
			   XdbWidgetGeometry2String(&wants),
			   XdbWidgetGeometry2String(reply)));

	return XtGeometryAlmost;
    }
}

static void
change_managed(Widget w)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "change_managed()\n"));

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmRCAdjustSize from change_managed\n"));

    _XmRCAdjustSize(w, NULL, NULL);

    _XmNavigChangeManaged(w);
}

static void
MenuProcEntry(int proc, Widget w,...)
{
    Display *dpy = XtDisplay(w);

    switch (proc)
    {
    case XmMENU_POPDOWN:
	break;

    case XmMENU_PROCESS_TREE:
	break;

    case XmMENU_TRAVERSAL:
	break;

    case XmMENU_SHELL_POPDOWN:
	break;

    case XmMENU_CALLBACK:
	break;

    case XmMENU_BUTTON:
	break;

    case XmMENU_CASCADING:
	break;

    case XmMENU_SUBMENU:
	break;

    case XmMENU_ARM:
	/* grab the keyboard and freeze everything so that we can be sure that
	   the next event goes to the right place. */

	_XmGrabKeyboard(w,
	/* owner_events */ True,
	/* Pointer mode */ GrabModeSync,
	/* Keyboard mode */ GrabModeSync,
	/* Timestamp */ CurrentTime);

#if 0
	/* FIX ME: seems to cause problems. Commented out for now. Not needed
	 * until menu keyboard traversal comes into play anyway
	 * -- PvH 97/05/31.
	 */

	/* get the window that previously had the focus
	   before popping up the menu so we can revert
	   to it after we're done. */

	_XmMenuFocus(w, XmMENU_FOCUS_SAVE, CurrentTime);

	_XmMenuFocus(w, XmMENU_FOCUS_SET, CurrentTime);
#endif

	XAllowEvents(dpy, AsyncKeyboard, CurrentTime);

	/* FIX ME: this should be _XmAddGrab, but that causes grab trouble. */
	XtAddGrab(w, True, True);

	/* Initiate a new pointer grab for the menu bar */
	/* Pointer mode will change to Sync anyway with the
	   XAllowEvents. It's also set here, according to xscope - Chris 6/23 */

	_XmGrabPointer(w, True,
		       (ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
			LeaveWindowMask),
		       GrabModeSync,
		       GrabModeAsync,
		       None,
		       XmGetMenuCursor(dpy),
		       CurrentTime);


	/* Process events until the next button event */
	XAllowEvents(dpy, SyncPointer, CurrentTime);

	RC_SetArmed(w, True);
	break;

    case XmMENU_DISARM:
	_XmUngrabPointer(w, CurrentTime);

	_XmUngrabKeyboard(w, CurrentTime);

	/* FIX ME: this should be _XmRemoveGrab, but that causes
	 * grab trouble.
	 */
	XtRemoveGrab(w);

	RC_SetArmed(w, False);

	break;

    case XmMENU_BAR_CLEANUP:
	break;

    case XmMENU_STATUS:
	break;

    case XmMENU_MEMWIDGET_UPDATE:
	break;

    case XmMENU_BUTTON_POPDOWN:
	break;

    case XmMENU_RESTORE_EXCLUDED_TEAROFF_TO_TOPLEVEL_SHELL:
	break;

    case XmMENU_RESTORE_TEAROFF_TO_TOPLEVEL_SHELL:
	break;

    case XmMENU_RESTORE_TEAROFF_TO_MENUSHELL:
	break;

    case XmMENU_GET_LAST_SELECT_TOPLEVEL:
	break;

    case XmMENU_TEAR_OFF_ARM:
	break;

    default:
	break;
    }
}

static void
ArmAndActivate(Widget w, XEvent *e, String *args, Cardinal *nargs)
{
}

/* rws add callbacks to sub menu */
void
_XmFixOptionMenu(Widget new_w, Boolean use_set_values)
{
    /* rws
     * Add an activateCallback to all the children of the menu
     * display the label of the menuHistory or first item
     * set menuHistory if necessary
     */

    XmString Label;
    int j;

    DEBUGOUT(XdbDebug(__FILE__, new_w, "_XmFixOptionMenu\n"));

    if (RC_OptionSubMenu(new_w))
    {
	for (j = 0; j < MGR_NumChildren(RC_OptionSubMenu(new_w)); j++)
	{
	    if (XtHasCallbacks(MGR_Children(RC_OptionSubMenu(new_w))[j],
			       XmNactivateCallback) != XtCallbackNoList)
	    {
		XtAddCallback(MGR_Children(RC_OptionSubMenu(new_w))[j],
			      XmNactivateCallback, _XmOptionCallback, new_w);
	    }
	}

	/* Try to set a history. This may fail when the menu is empty */
	/* Crash prevention for test/Xm/scrolledwindow/test13 */
	if (RC_MemWidget(new_w) == NULL)
	{
	    if (MGR_NumChildren(RC_OptionSubMenu(new_w)))
	    {

		RC_MemWidget(new_w) =
		    MGR_Children(RC_OptionSubMenu(new_w))[0];

		DEBUGOUT(XdbDebug2(__FILE__, new_w, RC_MemWidget(new_w),
				   "_XmFixOptionMenu: Set RC_MemWidget\n"));
	    }
	}

	if (RC_MemWidget(new_w) != NULL)
	{
	    Widget button;

	    XtVaGetValues(RC_MemWidget(new_w), XmNlabelString, &Label,
			  NULL);

	    /*
	     * OK, here's the fix for the bug demonstrated in
	     * test/Xm/rowcolumn/test26.c.  The error is in the
	     * usage of _XmFixOptionMenu in CascadeBG's initialize() and
	     * set_values() methods.
	     */
	    if ((button = XmOptionButtonGadget(new_w)) != NULL)
	    {
		if (use_set_values)
		{
		    XtVaSetValues(button,
				  XmNlabelString, Label,
				  NULL);

		    /* rws 27 Apr 1997 label should be freed, no??? */
		    XmStringFree(Label);
		}
		else
		{
		    if (_XmStringIsXmString((XmString)LabG_Label(button)))
		    {
			XmStringFree((XmString)LabG_Label(button));
		    }
		    else
		    {
			_XmStringFree(LabG_Label(button));
		    }

		    if (_XmStringIsXmString(Label))
		    {
			LabG_Label(button) = _XmStringCreate(Label);
			XmStringFree(Label);
		    }
		    else
		    {
			LabG_Label(button) = (_XmString)Label;
		    }
		}
	    }
	}
    }
}

/* rws Option menu callback */
static void
_XmOptionCallback(Widget w,
		  XtPointer cd,
		  XtPointer cs)
{
    XmString ButtonLabel;
    Widget rc = (Widget)cd;

    XtVaGetValues(w, XmNlabelString, &ButtonLabel,
		  NULL);
    XtVaSetValues(XmOptionButtonGadget(rc), XmNlabelString, ButtonLabel,
		  NULL);

    RC_MemWidget(rc) = w;

    XmStringFree(ButtonLabel);
}

void
_XmRadioCallback(Widget w,
		 XtPointer cd,
		 XtPointer cs)
{
    Widget tgl;
    Widget rc = (Widget)cd;
    XmToggleButtonCallbackStruct *cbs = (XmToggleButtonCallbackStruct *)cs;
    int i;

    if (cbs == NULL || !RC_RadioBehavior(rc))
    {
	DEBUGOUT(XdbDebug2(__FILE__, rc, w, "_XmRadioCallback (NULL)\n"));
	return;
    }

    DEBUGOUT(XdbDebug2(__FILE__, rc, w, "_XmRadioCallback\n"));

    if (RC_RadioAlwaysOne(rc) && cbs->set == False)
    {
	int cnt = 0;

	for (i = 0; i < MGR_NumChildren(rc); i++)
	{
	    tgl = MGR_Children(rc)[i];
	    if (XmIsToggleButton(tgl) && XmToggleButtonGetState(tgl))
	    {
		cnt++;
	    }
	    else if (XmIsToggleButtonGadget(tgl) &&
		     XmToggleButtonGadgetGetState(tgl))
	    {
		cnt++;
	    }
	}
	if (cnt == 0)
	{
	    /* Whow. You're resetting the radio box without written permission.
	     * Stop right there ! */
	    if (XmIsToggleButton(w))
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			"_XmRadioCallback: toggle -> True\n"));
		_XmToggleButtonSetState(w, True);
	    }
	    else if (XmIsToggleButtonGadget(w))
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			"_XmRadioCallback: toggle -> True\n"));
		_XmToggleButtonGadgetSetState(w, True);
	    }

	    return;
	}
    }

    for (i = 0; i < MGR_NumChildren(rc); i++)
    {
	tgl = MGR_Children(rc)[i];
	if (XmIsToggleButton(tgl) && XmToggleButtonGetState(tgl))
	{
	    if (w != tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle -> False\n"));
		_XmToggleButtonSetState(tgl, False);
	    }
	    else if (w == tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle -> True\n"));
		_XmToggleButtonSetState(tgl, True);
	    }
	}
	else if (XmIsToggleButtonGadget(tgl) &&
		 XmToggleButtonGadgetGetState(w))
	{
	    if (w != tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle -> False\n"));
		_XmToggleButtonGadgetSetState(tgl, False);
	    }
	    else if (w == tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle -> True\n"));
		_XmToggleButtonGadgetSetState(tgl, True);
	    }
	}
    }
}

static void
_XmEntryCallback(Widget w,
		 XtPointer cd,
		 XtPointer cs)
{
    XmRowColumnCallbackStruct rcb;
    XmToggleButtonCallbackStruct *cbs = (XmToggleButtonCallbackStruct *)cs;
    Widget rc = (Widget)cd;

    rcb.reason = XmCR_ACTIVATE;
    rcb.event = cbs->event;
    rcb.widget = w;
    rcb.data = (char *)cd;
    rcb.callbackstruct = (char *)cs;
    XtCallCallbackList(rc, RC_Entry_cb(rc), (XtPointer)&rcb);
}

static Cardinal
_XmRowColumnOrderProc(Widget widget)
{
    if (RCC_PositionIndex(widget) == XmLAST_POSITION ||
	RCC_PositionIndex(widget) >=
	MGR_NumChildren(XtParent(widget)))
    {
	return MGR_NumChildren(XtParent(widget));
    }
    else
    {
	return RCC_PositionIndex(widget);
    }
}

static void
insert_child(Widget w)
{
    Widget rc = (Widget)XtParent(w);
    int i;
    extern void dump_boxes();

#if 0
    if ((RC_RadioBehavior(rc) || RC_RadioAlwaysOne(rc)) &&
	((XtClass(w) == xmToggleButtonWidgetClass) ||
	 (XtClass(w) == xmToggleButtonGadgetClass)))
    {
	XtAddCallback(w, XmNvalueChangedCallback, _XmRadioCallback, rc);
    }
#endif

#define superclass (&xmManagerClassRec)
    (*superclass->composite_class.insert_child) (w);
#undef superclass

    for (i = 0; i < MGR_NumChildren(rc); i++)
    {
	RCC_PositionIndex(MGR_Children(rc)[i]) = i;
    }

    DEBUGOUT(XdbDebug2(__FILE__, rc, w, "InsertChild\n"));

    /*
     * if it's a label subclass, set its alignment to our
     * RC_EntryAlignment resource
     */
    if (RC_IsAligned(rc) &&
	(XmIsLabel(w) || XmIsLabelGadget(w)))
    {
	Arg arg;

	XtSetArg(arg, XmNalignment, RC_EntryAlignment(rc));
	XtSetValues(w, &arg, 1);
	DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			   "insert_child: Set Alignment to %s\n",
			   XdbAlignment2String(RC_EntryAlignment(rc))));
    }

    if (RC_Entry_cb(rc))
    {
	if (XmIsDrawnButton(w))
	{
	    if (DB_ActivateCallback(w))
	    {
		XtRemoveCallbacks(w, XmNactivateCallback,
				  DB_ActivateCallback(w));
	    }
	    XtAddCallback(w, XmNactivateCallback, _XmEntryCallback, rc);
	}
	else if (XmIsCascadeButton(w))
	{
	    if (CB_ActivateCall(w))
	    {
		XtRemoveCallbacks(w, XmNactivateCallback, CB_ActivateCall(w));
	    }
	    XtAddCallback(w, XmNactivateCallback, _XmEntryCallback, rc);
	}
	else if (XmIsCascadeButtonGadget(w))
	{
	    if (CBG_ActivateCall(w))
	    {
		XtRemoveCallbacks(w, XmNactivateCallback, CBG_ActivateCall(w));
	    }
	    XtAddCallback(w, XmNactivateCallback, _XmEntryCallback, rc);
	}
	else if (XmIsPushButton(w))
	{
	    if (PB_ActivateCallback(w))
	    {
		XtRemoveCallbacks(w, XmNactivateCallback,
				  PB_ActivateCallback(w));
	    }
	    XtAddCallback(w, XmNactivateCallback, _XmEntryCallback, rc);
	}
	else if (XmIsPushButtonGadget(w))
	{
	    if (PBG_ActivateCallback(w))
	    {
		XtRemoveCallbacks(w, XmNactivateCallback,
				  PBG_ActivateCallback(w));
	    }
	    XtAddCallback(w, XmNactivateCallback, _XmEntryCallback, rc);
	}
	else if (XmIsToggleButton(w))
	{
	    if (TB_ValueChangedCallback(w))
	    {
#ifdef	WHOW
		/* Insane */
		fprintf(stderr, "Whow (%d)\n",
			((XmToggleButtonWidget)w)->toggle.value_changed_CB->callback);
		if (((XmToggleButtonWidget)w)->toggle.value_changed_CB->callback == 1) {
		    fprintf(stderr, "Whow\n");
		    ((XmToggleButtonWidget)w)->toggle.value_changed_CB = NULL;
		}
#endif
		XtRemoveCallbacks(w, XmNvalueChangedCallback,
				  TB_ValueChangedCallback(w));
	    }
	    XtAddCallback(w, XmNvalueChangedCallback, _XmEntryCallback, rc);
	}
	else if (XmIsToggleButtonGadget(w))
	{
	    if (TBG_ValueChangedCallback(w))
	    {
#ifdef WHOW
		/* Insane */
		fprintf(stderr, "Whow (%d)\n",
			((XmToggleButtonGadget)w)->toggle.value_changed_CB->callback);
		if (((XmToggleButtonGadget)w)->toggle.value_changed_CB->callback == 1) {
		    fprintf(stderr, "Whow\n");
		    ((XmToggleButtonGadget)w)->toggle.value_changed_CB = NULL;
		}
#endif
		XtRemoveCallbacks(w, XmNvalueChangedCallback,
				  TBG_ValueChangedCallback(w));
	    }
	    XtAddCallback(w, XmNvalueChangedCallback, _XmEntryCallback, rc);
	}
    }

    if (XmIsTearOffButton(w))
    {
	RC_TearOffControl(rc) = w;
	DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			   "InsertChild: this is the TearOff control\n"));
    }

    /* Option Menu : handle inserting children */
    if (RC_CascadeBtn(rc))
    {
	Widget p = XtParent(RC_CascadeBtn(rc));
	if (p && XmIsRowColumn(p) && RC_Type(p) == XmMENU_OPTION)
	{
	    _XmFixOptionMenu(p, True);
	}
    }
}

static void
delete_child(Widget w)
{
    Widget rc = XtParent(w);
    int i;

    DEBUGOUT(XdbDebug2(__FILE__, rc, w, "DeleteChild\n"));

#define	superclass	(&xmManagerClassRec)
    (*superclass->composite_class.delete_child) (w);
#undef superclass

    for (i = 0; i < MGR_NumChildren(rc); i++)
    {
	RCC_PositionIndex(MGR_Children(rc)[i]) = i;
    }
}

static void
constraint_initialize(Widget request, Widget new_w,
		      ArgList args, Cardinal *num_args)
{
    Dimension *baselines;
    int num_baselines;

    DEBUGOUT(XdbDebug(__FILE__, new_w, "constraint_initialize\n"));

    RCC_MarginTop(new_w) = RCC_MarginBottom(new_w) = 0;
    if (XmIsLabel(new_w))
    {
	if (RC_Orientation(XtParent(new_w)) == XmHORIZONTAL)
	{
	    RCC_MarginTop(new_w) = Lab_MarginTop(new_w);
	    RCC_MarginBottom(new_w) = Lab_MarginBottom(new_w);
	}
	else
	{
	    RCC_MarginTop(new_w) = Lab_MarginLeft(new_w);
	    RCC_MarginBottom(new_w) = Lab_MarginRight(new_w);
	}
    }
    else if (XmIsLabelGadget(new_w))
    {
	if (RC_Orientation(XtParent(new_w)) == XmHORIZONTAL)
	{
	    RCC_MarginTop(new_w) = LabG_MarginTop(new_w);
	    RCC_MarginBottom(new_w) = LabG_MarginBottom(new_w);
	}
	else
	{
	    RCC_MarginTop(new_w) = LabG_MarginLeft(new_w);
	    RCC_MarginBottom(new_w) = LabG_MarginRight(new_w);
	}
    }

    /* we set the baseline of the child to the lowest baseline of the widget */
    if (XmWidgetGetBaselines(new_w, &baselines, &num_baselines))
    {
	RCC_Baseline(new_w) = baselines[num_baselines - 1];
	XtFree((char *)baselines);
    }
    else
    {
	/* is this right ? */
	RCC_Baseline(new_w) = 0;
    }
}


static Boolean
constraint_set_values(Widget current, Widget request, Widget new_w,
		      ArgList args, Cardinal *num_args)
{
    Dimension *baselines;
    int num_baselines;
    Boolean refresh_needed = False;
    int i;
    Widget rc = XtParent(new_w);

    DEBUGOUT(XdbDebug(__FILE__, new_w, "constraint_set_values\n"));

    if (RCC_PositionIndex(new_w) != RCC_PositionIndex(current))
    {
	Widget savew;
	int pos, lastpos;

	pos = RCC_PositionIndex(new_w);
	lastpos = RCC_PositionIndex(current);

	if (RCC_PositionIndex(new_w) == XmLAST_POSITION)
	{
	    RCC_PositionIndex(new_w) = MGR_NumChildren(rc) - 1;
	    pos = RCC_PositionIndex(new_w);
	}

	savew = MGR_Children(rc)[lastpos];

	if (pos < lastpos)
	{
	    for (i = lastpos; i > pos; i--)
	    {
		MGR_Children(rc)[i] = MGR_Children(rc)[i - 1];
	    }

	    MGR_Children(rc)[pos] = savew;
	}
	else if (pos > lastpos)
	{
	    for (i = lastpos; i < pos; i++)
	    {
		MGR_Children(rc)[i] = MGR_Children(rc)[i + 1];
	    }

	    MGR_Children(rc)[pos] = savew;
	}

	for (i = 0; i < MGR_NumChildren(rc); i++)
	{
	    RCC_PositionIndex(MGR_Children(rc)[i]) = i;
	}

	DEBUGOUT(XdbDebug(__FILE__, new_w,
			  "_XmRCAdjustSize from constraint_set_values\n"));
	_XmRCAdjustSize(rc, NULL, NULL);

	refresh_needed = True;
    }

    RCC_MarginTop(new_w) = RCC_MarginBottom(new_w) = 0;
    if (XmIsLabel(new_w))
    {
	if (RC_Orientation(XtParent(new_w)) == XmHORIZONTAL)
	{
	    RCC_MarginTop(new_w) = Lab_MarginTop(new_w);
	    RCC_MarginBottom(new_w) = Lab_MarginBottom(new_w);
	}
	else
	{
	    RCC_MarginTop(new_w) = Lab_MarginLeft(new_w);
	    RCC_MarginBottom(new_w) = Lab_MarginRight(new_w);
	}
    }
    else if (XmIsLabelGadget(new_w))
    {
	if (RC_Orientation(XtParent(new_w)) == XmHORIZONTAL)
	{
	    RCC_MarginTop(new_w) = LabG_MarginTop(new_w);
	    RCC_MarginBottom(new_w) = LabG_MarginBottom(new_w);
	}
	else
	{
	    RCC_MarginTop(new_w) = LabG_MarginLeft(new_w);
	    RCC_MarginBottom(new_w) = LabG_MarginRight(new_w);
	}
    }

    /* we set the baseline of the child to the lowest baseline of the widget */
    if (XmWidgetGetBaselines(new_w, &baselines, &num_baselines))
    {
	RCC_Baseline(new_w) = baselines[num_baselines - 1];
	XtFree((char *)baselines);
    }
    else
    {
	/* is this right ? */
	RCC_Baseline(new_w) = 0;
    }

    return refresh_needed;
}

static XmNavigability
widget_navigable(Widget w)
{
    if (XtSensitive(w) && MGR_TraversalOn(w) &&
	(RC_Type(w) == XmWORK_AREA || RC_Type(w) == XmMENU_OPTION))
    {
	if ((MGR_NavigationType(w) == XmSTICKY_TAB_GROUP ||
	     MGR_NavigationType(w) == XmEXCLUSIVE_TAB_GROUP ||
	     MGR_NavigationType(w) == XmTAB_GROUP) && !_XmShellIsExclusive(w))
	{
	    return XmDESCENDANTS_TAB_NAVIGABLE;
	}

	return XmDESCENDANTS_NAVIGABLE;
    }

    return XmNOT_NAVIGABLE;
}

/* Determine if widget w is a top level menu pane/bar, and that the given event
 * (assumed to be a button event !) occured outside widget w's child widgets */
static Boolean
ExternalBtnEvent(Widget w,
		 XEvent *event)
{
    Widget event_widget;
    Boolean is_child = False;

    /* Determine the top-level widget for 'w' */
    Widget w_top_level = RC_LastSelectToplevel(w);

    DEBUGOUT(XdbDebug(__FILE__, w,
		      " Determining if the button event was external "
		      "to the menu system\n"));

    /* Determine if w is a top level menu pane/bar */
    if ((w_top_level == w) || !w_top_level)
    {
	/* Determine the event window */
	Window event_window = (event->xbutton.subwindow) ?
	event->xbutton.subwindow : event->xbutton.window;

	/* Convert window to a widget ID */
	event_widget = XtWindowToWidget(XtDisplay(w), event_window);

	/* Now determine if the event widget is a child (direct of indirect)
	 * of widget w. */
	if (event_widget && (event_widget != w))
	{
	    Widget parent = XtParent(event_widget);

	    /* Search event widgets parents, to see if 'w' is an ancestor */
	    while (parent && (parent != w))
	    {
		parent = XtParent(parent);
	    }

	    is_child = (parent == w);
	}			/* if event widget is not 'w' */
    }				/* If event widget is a top level menu pane/bar */

    return (!is_child);
}

/* action routines */

static void
MenuBtnDown(Widget w,
	    XEvent *event,
	    String *params,
	    Cardinal *num_params)
{
    Widget gadget;

    /* FIX ME: This will prevent a freeze when clicking a insensitive
     * menu item. Don't know if this is the proper place.
     */
    XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);

    if (!_XmIsEventUnique(event))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "HEY, Got ButtonPress event for the second time!\n"));
	return;
    }

    /* If event was in a child gadget, then arm it, otherwise determine
     * whether the event occured outside the menu system, and do a cleanup
     * if it did. */
    gadget = (Widget)_XmInputForGadget(w,
				       event->xkey.x,
				       event->xkey.y);

    if (gadget && event->xbutton.window == XtWindow(w))
    {
	/* Event was in a gadget */
	DEBUGOUT(XdbDebug2(__FILE__, w, gadget, "MenuBtnDown() in gadget\n"));

	MGR_HighlightedWidget(w) = gadget;

	/* turn on mouse traversal */
	_XmSetInDragMode(w, True);

	/* Now we arm the widget */

	/* FIX ME: this used to be _XmGadgetArm(), it seems to be a good
	 * thing to bypass traversal logic, 'cause we get a XAllowEvents
	 * this way.
	 */

	_XmDispatchGadgetInput((Widget)gadget, event, XmARM_EVENT);
    }
    else if (ExternalBtnEvent(w, event))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "MenuBtnDown(event external to menu system)\n"));
	/*
	 * Event was external to the menu system;
	 * Do a cleanup, and replay the event to the outside world.
	 */
	DoBtnEventCleanupReplay(w, event, params, num_params);
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "MenuBtnDown(not in gadget)\n"));
    }
}

static void
DoBtnEventCleanupReplay(Widget w,
			XEvent *event,
			String *params,
			Cardinal *num_params)
{
    Widget menu_shell;
    Widget tlrc;

    DEBUGOUT(XdbDebug(__FILE__, w, "DoBtnEventCleanupReplay\n"));

    _XmGetActiveTopLevelMenu(w, &tlrc);

    if (!tlrc)
    {
	return;			/* FIX ME */
    }

    menu_shell = XtParent(tlrc);

    DEBUGOUT(XdbDebug(__FILE__, w,
		   "DoBtnEventCleanupReplay: calling MenuShellPopdownDone\n"));
    XtCallActionProc(menu_shell, "MenuShellPopdownDone",
		     event, params, *num_params);

    _XmSetInDragMode(w, False);

    /* Replay the event */
    DEBUGOUT(XdbDebug(__FILE__, w,
		      "DoBtnEventCleanupReplay: XAllowEvents (replay)\n"));

    /* FIX ME: should depend on resource */
    /* FIX ME: doesn't work */
    XAllowEvents(XtDisplay(w), ReplayPointer, CurrentTime);
}

static void
MenuBtnUp(Widget w,
	  XEvent *event,
	  String *params,
	  Cardinal *num_params)
{
    Widget gadget;

    /* FIX ME: When ButtonUp in insensitive menu item, menus stays in
     * drag mode.
     */

    /* FIX ME: This will prevent a freeze when clicking a insensitive
     * menu item. Don't know if this is the proper place.
     */
    XAllowEvents(XtDisplay(w), SyncPointer, CurrentTime);

    /* FIX ME: are these recorded? */
    if (!_XmIsEventUnique(event))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
		       "HEY, Got ButtonRelease event for the second time!\n"));

	return;
    }

    /*
     * If event was in a child gadget, then arm it, otherwise determine
     * whether the event occured outside the menu system, and do a cleanup
     * if it did.
     */
    gadget = (Widget)_XmInputForGadget(w,
				       event->xkey.x,
				       event->xkey.y);

    if (gadget && event->xbutton.window == XtWindow(w))
    {

	DEBUGOUT(XdbDebug2(__FILE__, w, gadget, "MenuBtnUp(in gadget)\n"));

	_XmSetInDragMode(w, False);

	/* Now we activate the gadget */
	/* FIX ME: this used to be _XmGadgetActivate(), it seems to be a good
	 * thing to bypass traversal logic, 'cause we get a XAllowEvents
	 * this way.
	 */

	_XmDispatchGadgetInput((Widget)gadget, event, XmACTIVATE_EVENT);
    }
    else if (ExternalBtnEvent(w, event))
    {

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "MenuBtnUp(event external to menu system)\n"));

	/*
	 * Event was external to the menu system;
	 * Do a cleanup, and replay the event to the outside world.
	 */
	DoBtnEventCleanupReplay(w, event, params, num_params);
    }
    else
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "MenuBtnUp(not in gadget)\n"));
    }
}

/* FIX ME: this should happen from XmMenuShell:_XmEnterRowColumn */
static void
MenuEnter(Widget w,
	  XEvent *event,
	  String *params,
	  Cardinal *num_params)
{
    /* FIX ME: this might make the enter code of some of the
     * menu items redundant.
     */

    DEBUGOUT(XdbDebug(__FILE__, w, "MenuEnter()\n"));

    /* FIX ME: Hu? the test for popup doesn't seem to be always needed..
     * Should this be handled by translations?
     */
    if ((RC_Type(w) == XmMENU_PULLDOWN || RC_Type(w) == XmMENU_POPUP) &&
	_XmGetInDragMode(w) &&
	RC_PopupPosted(w))
    {
	Window subwindow = event->xcrossing.subwindow;
	int detail = event->xcrossing.detail;
	Boolean dont_popdown;
	Widget mw;

	/* Find out whether we entered a CascadeB[G]
	 * If it's not a CascadB[G] or if it is a CascadeB[G] but not the
	 * one that has the sub menu posted unpost our submenu
	 */

	if (detail == NotifyNonlinearVirtual)
	{
	    /* A child widget is entered.
	     * FIX ME: How about obscuring windows?
	     */

	    mw = XtWindowToWidget(XtDisplay(w), subwindow);

	    dont_popdown = XmIsCascadeButton(mw) &&
		RC_CascadeBtn(RC_PopupPosted(w)) == mw;
	}
	else
	{
	    mw = (Widget)_XmInputForGadget(w,
					   event->xcrossing.x,
					   event->xcrossing.y);

	    dont_popdown = mw &&
		XmIsCascadeButtonGadget(mw) &&
		RC_CascadeBtn(RC_PopupPosted(w)) == mw;

	}

	if (!dont_popdown)
	{
	    XtUnmanageChild(RC_PopupPosted(w));
	    RC_PopupPosted(w) = NULL;

	    /* FIX ME: more */
	}
    }
}

static void
MenuUnmap(Widget w,
	  XEvent *event,
	  String *params,
	  Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuUnmap()\n"));

    MGR_HighlightedWidget(w) = NULL;	/* FIX ME: move elsewhere */

    _XmCallRowColumnUnmapCallback(w, event);
}

static void
MenuFocusIn(Widget w,
	    XEvent *event,
	    String *params,
	    Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuFocusIn\n"));
}

static void
MenuFocusOut(Widget w,
	     XEvent *event,
	     String *params,
	     Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuFocusOut\n"));
    /* restore the focus to the widget that had it before moving to the menu bar */
}

static void
MenuBarEnter(Widget w,
	     XEvent *event,
	     String *params,
	     Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuBarEnter()\n"));
}

static void
MenuBarLeave(Widget w,
	     XEvent *event,
	     String *params,
	     Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuBarLeave()\n"));
}

static void
MenuBarGadgetSelect(Widget w,
		    XEvent *event,
		    String *params,
		    Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuBarGadgetSelect()\n"));
}

/*
 * most of these are already written under different names
 */
void
_XmPostPopupMenu(Widget wid,
		 XEvent *event)
{
    if (!XmIsRowColumn(wid)
	|| RC_Type(wid) != XmMENU_POPUP)
    {
	_XmWarning(wid,
		   "_XmPostPopupMenu sent non rowcolumn widget\n");

	return;
    }

    _XmSetInDragMode(wid, True);
    _XmMenuSetInPMMode(wid, True);

    XtPopupSpringLoaded(XtParent(wid));
}

void
_XmSetPopupMenuClick(Widget wid,
		     Boolean popupMenuClick)
{
}

Boolean
_XmGetPopupMenuClick(Widget wid)
{
    return False;
}

void
_XmAllowAcceleratedInsensitiveUnmanagedMenuItems(Widget wid,
						 Boolean allowed)
{
    XmMenuState state = _XmGetMenuState(wid);

    state->RC_allowAcceleratedInsensitiveUnmanagedMenuItems = allowed;
}

void
_XmSetSwallowEventHandler(Widget widget,
			  Boolean add_handler)
{
}

void
_XmMenuFocus(Widget w,
	     int operation,
	     Time _time)
{
    XmMenuState state = _XmGetMenuState(w);
    Window window_return;
    int revert_to_return;
    /* nothing but a guess here.  There are three operations that seem
       to take place with respect to focus and menus.

       1 - saving the keyboard focus (done at the start of the menu stuff.)
       2 - setting the keyboard focus (done at several points.)
       3 - restoring the keyboard focus (done at the end of the menu stuff.)

       So, those are the three "operations" that are valid to this function.
     */
    switch (operation)
    {
    case XmMENU_FOCUS_SAVE:
	XGetInputFocus(XtDisplay(w),
		       &state->RC_menuFocus.oldFocus,
		       &state->RC_menuFocus.oldRevert);

	state->RC_menuFocus.oldWidget = XtWindowToWidget(XtDisplay(w),
						 state->RC_menuFocus.oldFocus);
	break;

    case XmMENU_FOCUS_RESTORE:
	XSetInputFocus(XtDisplay(w),
		       state->RC_menuFocus.oldFocus,
		       state->RC_menuFocus.oldRevert,
		       _time);

	XGetInputFocus(XtDisplay(w),
		       &window_return,
		       &revert_to_return);

	if (state->RC_menuFocus.oldFocus != window_return
	    || state->RC_menuFocus.oldRevert != revert_to_return)
	{
	    DEBUGOUT(XdbDebug(__FILE__, w, "  SetInputFocus call failed.\n"));
	}
	break;

    case XmMENU_FOCUS_SET:
	XSetInputFocus(XtDisplay(w),
		       XtWindow(w),
		       RevertToPointerRoot,
		       _time);

	XGetInputFocus(XtDisplay(w),
		       &window_return,
		       &revert_to_return);

	if (window_return != XtWindow(w)
	    || revert_to_return != RevertToPointerRoot)
	{
	    DEBUGOUT(XdbDebug(__FILE__, w, "  setting input focus failed\n"));
	    _XmUngrabKeyboard(w, _time);
	    return;
	}

	break;
    }
}

void
_XmGetActiveTopLevelMenu(Widget wid,
			 Widget *rwid)
{
#if 0
    if (RC_LastSelectToplevel(wid) == NULL)
    {
	*rwid = wid;
    }
    else
    {
	if (XmIsMenuShell(XtParent(RC_LastSelectToplevel(wid))))
	{
	    *rwid = RC_LastSelectToplevel(wid);
	}
	else
	{
	    *rwid = wid;
	}
    }
    return;
#else
    Widget toplevelrc;

    /* find the topmost menu pane */
    if ((toplevelrc = RC_LastSelectToplevel(wid)))
    {
	/* Pulldown and option menus keep track over their toplevel
	 * RowColumn...
	 */
	Widget top_pane;

	if ((top_pane = RC_PopupPosted(toplevelrc)))
	{
	    toplevelrc = top_pane;
	}
	else
	{
	    toplevelrc = NULL;	/* FIX ME */
	}
    }
    else
    {
	/* ... popup menus don't . */
	Widget cb;

	toplevelrc = wid;
	cb = RC_CascadeBtn(toplevelrc);

	while (cb)
	{
	    toplevelrc = XtParent(cb);
	    cb = RC_CascadeBtn(toplevelrc);
	}
    }

    *rwid = toplevelrc;
#endif
}

Boolean
_XmMatchBSelectEvent(Widget wid,
		     XEvent *event)
{
    return False;
}

Boolean
_XmMatchBDragEvent(Widget wid,
		   XEvent *event)
{
    return False;
}

void
_XmHandleMenuButtonPress(Widget wid,
			 XEvent *event)
{
}

void
_XmMenuBtnDown(Widget wid,
	       XEvent *event,
	       String *params,
	       Cardinal *num_params)
{
}

void
_XmMenuBtnUp(Widget wid,
	     XEvent *event,
	     String *params,
	     Cardinal *num_params)
{
}

void
_XmCallRowColumnMapCallback(Widget wid, XEvent *event)
{
    XmRowColumnCallbackStruct cbs;

    cbs.reason = XmCR_MAP;
    cbs.event = event;
    cbs.widget = NULL;
    cbs.data = NULL;
    cbs.callbackstruct = NULL;

    XtCallCallbackList(wid, RC_Map_cb(wid), (XtPointer)&cbs);
}

void
_XmCallRowColumnUnmapCallback(Widget wid, XEvent *event)
{
    XmRowColumnCallbackStruct cbs;

    cbs.reason = XmCR_UNMAP;
    cbs.event = event;
    cbs.widget = NULL;
    cbs.data = NULL;
    cbs.callbackstruct = NULL;

    XtCallCallbackList(wid, RC_Unmap_cb(wid), (XtPointer)&cbs);
}

void
_XmMenuPopDown(Widget w,
	       XEvent *event,
	       Boolean *popped_up)
{
}

Boolean
_XmIsActiveTearOff(Widget w)
{
    return RC_TearOffActive(w);
}

void
_XmMenuHelp(Widget w,
	    XEvent *event,
	    String *params,
	    Cardinal *num_params)
{
    XtCallCallbacks(w,
		    XmNhelpCallback,
		    NULL);
}

/* synthetic resource converters */
static XmImportOperator
_XmToMenuPost(Widget widget,
	      int offset,
	      XtArgVal *value)
{
    String menuPost = (String)*value;	/* the string we're checking/parsing. */
    Boolean valid_expression = True;	/* we're optimistic :) */
    int numberIndex = 0;	/* the index of the button number */
    int button = 0;

    DEBUGOUT(XdbDebug(__FILE__, widget, "In _XmToMenuPost(%s)\n", menuPost));

    if (menuPost == NULL)
    {
	DEBUGOUT(XdbDebug(__FILE__, widget,
			  "  Default case -- menupost == null\n"));
	return XmSYNTHETIC_NONE;
    }

    /* first we check the basic syntax of the expression. 
       for now we only allow things of the type <(Btn|Button)[0-5](Down)?> */

    if (valid_expression)
    {
	if (!strncmp(menuPost, "<Btn", 4))
	    numberIndex = 4;
	else if (!strncmp(menuPost, "<Button", 7))
	    numberIndex = 7;
	else
	{
	    DEBUGOUT(XdbDebug(__FILE__, widget,
			      "  Invalid beginning of string.\n"));
	    valid_expression = False;
	}
    }

    if (valid_expression)
    {
	if (numberIndex + 1 >= strlen(menuPost))
	{
	    DEBUGOUT(XdbDebug(__FILE__, widget,
			      "  Invalid ending of string.\n"));
	    valid_expression = False;
	}
	else if (!strncmp(&(menuPost[numberIndex + 1]), "Down>", 5))
	{
	    valid_expression = True;
	}
	else if (menuPost[numberIndex + 1] == '>')
	{
	    valid_expression = True;
	}
	else
	{
	    DEBUGOUT(XdbDebug(__FILE__, widget,
			      "  Invalid ending of string.\n"));
	    valid_expression = False;
	}
    }

    if (valid_expression)
    {
	button = menuPost[numberIndex] - '0';

	if (button < 1 || button > 5)
	{
	    DEBUGOUT(XdbDebug(__FILE__, widget,
			      "  Invalid button in string.\n"));
	    valid_expression = False;
	}
    }

    if (valid_expression)
    {
	DEBUGOUT(XdbDebug(__FILE__, widget,
			  "  Valid expression.  Button is %d\n", button));

	*value = (XtArgVal)menuPost;
	/* does this one ever change? */
	RC_PostEventType(widget) = ButtonPressMask;
	RC_PostButton(widget) = button;
	RC_PostModifiers(widget) = 0;	/* FIX ME */

	return XmSYNTHETIC_LOAD;
    }
    else
    {
	return XmSYNTHETIC_NONE;
    }
}

static void
_XmFromMenuPost(Widget widget,
		int offset,
		XtArgVal *value)
{
    /* This function assumes that the menuPost string is a button event.
       Not sure if this is in general the case.. FIX ME -- Chris */
    String return_value = (String)XtMalloc(sizeof(char)
					   * (strlen("<Btn>")
					      + 2	/* for the <>'s */
					      + 1 /* the the NULL */ ));

    DEBUGOUT(XdbDebug(__FILE__, widget, "In _XmFromMenuPost()\n"));

    sprintf(return_value, "<Btn%d>", RC_PostButton(widget));

    *value = (XtArgVal)return_value;
}

static void
_XmRowColumnEntryClassDefault(Widget w,
			      int offset,
			      XrmValue *val)
{
    static WidgetClass wclass;
/*    XmRowColumnWidget rc = (XmRowColumnWidget)w;

    if (RC_RadioBehavior(rc) && RC_Type(rc) == XmWORK_AREA)
	wclass = xmToggleButtonGadgetClass;
    else if (RC_Type(rc) == XmMENU_BAR)
	wclass = xmCascadeButtonClass;
    else
 *//* hmmm.... */ ;

    val->addr = (XtPointer)&wclass;
}

static void
_XmRowColumnIsHomogeneousDefault(Widget w,
				 int offset,
				 XrmValue *val)
{
    static Boolean homo;

    if ((RC_RadioBehavior(w) && RC_Type(w) == XmWORK_AREA) ||
	RC_Type(w) == XmMENU_BAR)
    {
	homo = True;
    }
    else
    {
	homo = False;
    }

    val->addr = (XtPointer)&homo;
}

static void
_XmRowColumnMenuAcceleratorDefault(Widget w,
				   int offset,
				   XrmValue *val)
{
    static String foo;

    if (!foo)
    {
	foo = XtNewString("foo");
    }

    val->addr = (XtPointer)&foo;
}

