/**
 *
 * $Id: RowColumn.c,v 1.147 1998/05/07 23:06:14 rwscott 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 const char rcsid[] = "$Id: RowColumn.c,v 1.147 1998/05/07 23:06:14 rwscott 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 <Xm/TearOffP.h>

#include <stdio.h>
#include <string.h>
#ifndef __STDC__
#include <varargs.h>
#else
#include <stdarg.h>
#endif
#include <assert.h>

#include <XmI/DebugUtil.h>

/* rws 5 May 1998
   TEST29 was a hack to get a back pointer from the pulldown in an option
   menu back to the option menu.  RC_LastSelectToplevel() should now contain
   this pointer for the pulldown. all of the ifdef TEST29 stuff should get
   removed.
 */
#define TEST29
#define ALWAYS_INSTALL_ENTRY_CALLBACK

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

static Boolean _XmRCdefaultIsAligned = True;
static Boolean _XmRCdefaultAdjustMargin = True;
static Boolean _XmRCdefaultRadioBehavior = False; /* This should be true according to misc/test16
                                                     But it messes up toggle buttons in menus!
                                                   */
static Boolean _XmRCdefaultRadioAlwaysOne = True;
static Boolean _XmRCdefaultIsHomogeneous = True;
static Boolean _XmRCdefaultPopupEnabled = True;

/* 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 initialize_posthook(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 AddPopupHandlers(Widget new_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);
*/


static void _XmPopupButtonPressHandler(Widget w, XtPointer client_data,
				       XEvent *event, Boolean *cont);

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

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

extern void _XmRCSetMargins(Widget w);

static 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),
	XmRBoolean, (XtPointer)&_XmRCdefaultIsAligned
	/* 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),
	XtRBoolean, (XtPointer)&_XmRCdefaultAdjustMargin
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNpacking, XmCPacking, XmRPacking,
	sizeof(unsigned char), Offset(packing),
	XmRImmediate, (XtPointer)XmUNSPECIFIED	/* To be overruled in initialize */
    },
    {
	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),
	XmRBoolean, (XtPointer)&_XmRCdefaultRadioBehavior
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNradioAlwaysOne, XmCRadioAlwaysOne, XmRBoolean,
	sizeof(Boolean), Offset(radio_one),
	XmRBoolean, (XtPointer)&_XmRCdefaultRadioAlwaysOne
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNisHomogeneous, XmCIsHomogeneous, XmRBoolean,
	sizeof(Boolean), Offset(homogeneous),
	XmRBoolean, (XtPointer)&_XmRCdefaultIsHomogeneous
	/*
	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),
	XmRBoolean, (XtPointer)&_XmRCdefaultPopupEnabled
	/*
	XmRImmediate, (XtPointer)True
	*/
	/* FIX ME: Motif has XmRBoolean, (XtPointer)whacko value */
    },
    {
	XmNmenuAccelerator, XmCAccelerators, XmRString,
	sizeof(String), Offset(menu_accelerator),
	XmRString, (XtPointer)""
	/*
	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,
    }
};

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(MenuBarGadgetSelect);
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 void _XmFocusOut(Widget, XEvent*, String*, Cardinal*);
static void _XmFocusIn(Widget, XEvent*, String*, Cardinal*);
static void _XmUnmap(Widget, XEvent*, String*, Cardinal*);
static void _XmNoop(Widget, XEvent*, String*, Cardinal*);

static XtActionsRec actions[] =
{

    {"MenuHelp", _XmMenuHelp},
    {"MenuBtnDown", _XmMenuBtnDown},
    {"MenuBtnUp", _XmMenuBtnUp},

    {"MenuBarGadgetSelect", MenuBarGadgetSelect},
    {"FocusOut", _XmFocusOut},
    {"FocusIn", _XmFocusIn},
    {"Unmap", _XmUnmap},
    {"Noop", _XmNoop},
    {"MenuTraverseLeft", _XmMenuTraverseLeft},
    {"MenuTraverseRight", _XmMenuTraverseRight},
    {"MenuTraverseUp", _XmMenuTraverseUp},
    {"MenuTraverseDown", _XmMenuTraverseDown},
    {"MenuEscape", _XmMenuEscape},
    {"MenuFocusIn", MenuFocusIn},
    {"MenuFocusOut", MenuFocusOut},
    {"MenuUnmap", MenuUnmap},
    {"MenuEnter", MenuEnter},
    /*{"MenuGadgetReturn", _XmMenuReturn},*/
    {"MenuGadgetEscape", _XmMenuEscape},
    {"MenuGadgetTraverseLeft", _XmRC_GadgetTraverseLeft},
    {"MenuGadgetTraverseRight", _XmRC_GadgetTraverseRight},
    {"MenuGadgetTraverseUp", _XmRC_GadgetTraverseUp},
    {"MenuGadgetTraverseDown", _XmRC_GadgetTraverseDown},
};

/* *INDENT-OFF* */
static XmBaseClassExtRec _XmRowColumnCoreClassExtRec =
{
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,
    /* version                   */ XmBaseClassExtVersion,
    /* size                      */ sizeof(XmBaseClassExtRec),
    /* initialize_prehook        */ initialize_prehook,
    /* set_values_prehook        */ XmInheritSetValuesPrehook /*NULL*/,
    /* initialize_posthook       */ initialize_posthook,
    /* set_values_posthook       */ XmInheritSetValuesPosthook /*NULL*/,
    /* secondary_object_class    */ XmInheritClass /*NULL*/,
    /* secondary_object_create   */ XmInheritSecObjectCreate /*NULL*/,
    /* get_secondary_resources   */ XmInheritGetSecResData /*NULL*/,
    /* fast_subclass             */ {0},
    /* get_values_prehook        */ XmInheritGetValuesPrehook /*NULL*/,
    /* get_values_posthook       */ XmInheritGetValuesPosthook /*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              */ XmInheritFocusChange,
    /* wrapper_data              */ NULL
};

#if 0
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
};
#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     */ XtExposeCompressMaximal /*XtExposeCompressMultiple*/,
	/* compress_enterleave   */ False /*True*/,
	/* visible_interest      */ False /*True*/,
	/* destroy               */ destroy,
	/* resize                */ resize,
	/* expose                */ expose,
	/* set_values            */ set_values,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ XtInheritSetValuesAlmost,
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ XtInheritTranslations, /* should be NULL but
	                                                      we loose togglebg's in
	                                                      a work area if it is 
	                                                      togglegb/test1 */
	/* query_geometry        */ query_geometry,
	/* display_accelerator   */ NULL /*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)NULL /*&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           */ XtInheritTranslations,
	/* syn_resources          */ syn_resources,
	/* num_syn_resources      */ XtNumber(syn_resources),
	/* syn_constraint_res     */ NULL,
	/* num_syn_constraint_res */ 0,
	/* parent_process         */ XmInheritParentProcess,
	/* extension              */ (XtPointer)&_XmRowColumnMClassExtRec
    },
    /* XmRowColumn Area part */
    {
	/* menuProcedures   */ MenuProcEntry,
	/* armAndActivate   */ ArmAndActivate,
	/* traversalHandler */ _XmMenuTraversalHandler,
	/* extension        */ NULL,
    },
};
/* *INDENT-ON* */


WidgetClass xmRowColumnWidgetClass = (WidgetClass)&xmRowColumnClassRec;


static XtTranslations menubar_trans;
static XtTranslations option_trans;
static XtTranslations menu_trans;
static XtTranslations menutrav_trans;

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

    menubar_trans = XtParseTranslationTable(_XmRowColumn_bar_table);
    option_trans = XtParseTranslationTable(_XmRowColumn_option_table);
    menu_trans = XtParseTranslationTable(_XmRowColumn_menu_table);
    menutrav_trans = XtParseTranslationTable(_XmRowColumn_menu_traversal_table);
}

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)
    {
	MGR_NavigationType(new_w) = XmTAB_GROUP;
    }
    else
    {
	MGR_NavigationType(new_w) = XmNONE;
    }

    MGR_TraversalOn(new_w) = True;

    /* this is needed for Xmt.  We probably ought to follow suit with
     * what we do in Label et. al. and override the translations here
     * rather than in initialize. */
    _XmSaveCoreClassTranslations(new_w);

    switch (RC_Type(new_w))
    {
    case XmMENU_PULLDOWN:
    case XmMENU_POPUP:
	CoreClassTranslations(new_w) = (String)menu_trans;
	break;

    case XmMENU_BAR:
	CoreClassTranslations(new_w) = (String)menubar_trans;
	break;

    case XmMENU_OPTION:
	CoreClassTranslations(new_w) = (String)option_trans;
	break;

    case XmWORK_AREA:
    /* rws 8 Mar 1998
       I think that we should be installing the Manager translations here.
       misc/test16 shows that Motif sets the tm_table entry to NULL. If we 
       do this toggle button gadgets in work areas will not activate.
       togglebg/test1
     */
    default:
	break;
    }
}

static void
initialize_posthook(Widget request, Widget new_w,
		    ArgList args, Cardinal *num_args)
{
    _XmRestoreCoreClassTranslations(new_w);

    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),
			     XmNmnemonic, RC_Mnemonic(new_w),
			     XmNmnemonicCharSet, RC_MnemonicCharSet(new_w),
			     NULL);
	}
	cb = XtVaCreateManagedWidget(RC_OPTION_CBG,
				     xmCascadeButtonGadgetClass,
				     new_w,
				     XmNsubMenuId, RC_OptionSubMenu(new_w),
				     XmNmnemonic, RC_Mnemonic(new_w),
				     XmNmnemonicCharSet,
					RC_MnemonicCharSet(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);
	}
    }
}

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)
    {
	if (MGR_ShadowThickness(new_w) == XmINVALID_DIMENSION)
	{
	    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) == XmMENU_PULLDOWN ||
	RC_Type(new_w) == XmMENU_POPUP ||
	RC_Type(new_w) == XmMENU_BAR)
    {
	XtOverrideTranslations(new_w, menutrav_trans);
    }

    if (RC_Type(new_w) == XmMENU_POPUP)
    {
	if (RC_PostButton(new_w) == XmUNSPECIFIED)
	{
	    RC_PostEventType(new_w) = ButtonPress;
	    RC_PostButton(new_w) = Button3; /* Fixme: this should be BMenu */
	    RC_PostModifiers(new_w) = 0;
	}
	AddPopupHandlers(new_w);
    }

    ((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;  /* widget id of the menu at the
    					     top of the heir
    					   */

    if (RC_Type(new_w) == XmMENU_BAR || RC_Type(new_w) == XmMENU_OPTION)
    {
	RC_LastSelectToplevel(new_w) = new_w;
	if (RC_OptionSubMenu(new_w))
	{
	    /* Make sure the sub-menu has a back pointer to the option menu */
	    RC_LastSelectToplevel(RC_OptionSubMenu(new_w)) = new_w;
	}
    }

    /* Internal widgets */

    RC_CascadeBtn(new_w) = NULL;	/* widget id of the cascade button
    					   that posted this menu
    					 */
    RC_PopupPosted(new_w) = NULL;	/* widget id of the menu posted from
    					   any button in this menu
    					 */

    /* Tear off stuff */
    RC_SetTornOff(new_w, False);
    RC_SetFromInit(new_w, False);
    RC_SetTearOffDirty(new_w, False);
    RC_SetTearOffActive(new_w, False);
    RC_ParentShell(new_w) = NULL;
    RC_TearOffControl(new_w) = NULL;
    if ((RC_Type(new_w) == XmMENU_POPUP || RC_Type(new_w) == XmMENU_PULLDOWN) &&
	RC_TearOffModel(new_w) == XmTEAR_OFF_ENABLED)
    {
	_XmRcCreateTearOffControl(new_w);
    }

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

    /* 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))));
    }

#if 0
    /* FIX ME: This should be enabled as soon as MGR_HighlightedWidget(w) =
     * NULL is moved from MenuUnmap to Manager's event handler.
     */
    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,
		      "set_values: %i args\n"
		      "\t    old X %5i Y %5i W %5i H %5i\n"
		      "\trequest X %5i Y %5i W %5i H %5i\n"
		      "\t  new_w X %5i Y %5i W %5i H %5i\n",
		      *num_args,
		      XtX(old), XtY(old),
		      XtWidth(old), XtHeight(old),
		      XtX(request), XtY(request),
		      XtWidth(request), XtHeight(request),
		      XtX(new_w), XtY(new_w),
		      XtWidth(new_w), XtHeight(new_w)));
    DEBUGOUT(XdbPrintArgList(__FILE__, new_w, args, *num_args, False));

    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_OptionLabel(new_w) != RC_OptionLabel(old))
    {
        int i;
 
        /* Oh yes this is very efficient :-( */
        for (i = 0; i < MGR_NumChildren(new_w); i++)
        {
            if (XmIsLabelGadget(MGR_Children(new_w)[i]) &&
		!XmIsCascadeButtonGadget(MGR_Children(new_w)[i]))
            {
		if (RC_OptionLabel(new_w) == NULL)
		{
		    XtUnmanageChild(MGR_Children(new_w)[i]);
		}
		else
		{
		    XtVaSetValues(MGR_Children(new_w)[i],
				  XmNlabelString, RC_OptionLabel(new_w), NULL);

		    if (!XtIsManaged(MGR_Children(new_w)[i]))
		    {
			XtManageChild(MGR_Children(new_w)[i]);

			need_relayout = True;
			need_refresh = True;
		    }
		}
 
                DEBUGOUT(XdbDebug2(__FILE__, new_w, MGR_Children(new_w)[i],
                                   "Assign OptionLabelString\n"));

                break;
            }
	}
    }

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

	/* Make sure the sub-menu has a back pointer to the option menu */
	RC_LastSelectToplevel(RC_OptionSubMenu(new_w)) = new_w;
	/* 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)
{
#define superclass (&xmManagerClassRec)
    (*superclass->core_class.realize) (w, value_mask, attributes);
#undef superclass
    if (XmIsMenuShell(XtParent(w)) && MS_PrivateShell(XtParent(w)))
    {
	/* if this is in a private menu shell it was managed during
	   insert_child.  However if someone (Mozilla's go menu)
	   un-realizes the menu and then realizes it again we must
	   make sure it is managed.
	 */
	XtManageChild(w);
    }
}

static void
resize(Widget w)
{
    DEBUGOUT(XdbDebug(__FILE__, w,
	"RC resize -> wid %d ht %d, call _XmRCAdjustSize\n",
	XtWidth(w), XtHeight(w)));

    if (XtWindow(w))
	XClearArea(XtDisplay(w), XtWindow(w),
		0, 0, XtWidth(w), XtHeight(w),
		False);

    RC_SetFromResize(w, 1);

    _XmRCAdjustSize(w, NULL, NULL);

    RC_SetFromResize(w, 0);
}

static void
expose(Widget w, XEvent *event, Region region)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "Expose (wid %d ht %d)\n",
		XtWidth(w), XtHeight(w)));

    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)
{
Widget tlm;

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

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

    _XmRCAdjustSize(w, NULL, NULL);

    /* rws 28 Apr 1998
       If widget w is a pulldown menu that is associated to an option menu
       we have a problem here.  The option menu XmNmenuHistory could be
       pointing to a widget that has just been un-managed.  This becomes
       a problem if the un-manage is the first step of a destroy.  If we 
       do not find the associated option menu and fix up its XmNmenuHistory
       it will be left pointing to a widget that has been destroyed.  What
       we need is some sort of pointer from the pulldown menu to the 
       option menu.  RC_CascadeBtn() could be used but, currently it is
       only valid when the pulldown is visible.  The same can be said
       for RC_LastSelectToplevel().

       RC_CascadeBtn() is set to NULL in MenuShell:MenuShellPopdownOne()
       RC_LastSelectToplevel() will be set correctly whenever the menu
	   gets popped up. If we ensure that it is set correctly whenever
	   the subMenuId of an option menu changes, that should do it!
     */
    {
    	tlm = RC_LastSelectToplevel(w);
    	if (tlm && RC_Type(tlm) == XmMENU_OPTION)
    	{
    	Widget mem;

    		mem = RC_MemWidget(tlm);
    		if (mem && !XtIsManaged(mem))
    		{
    		Widget new_mem;

    			/* need to pick a new memWidget */
    			new_mem = _XmMenuNextItem(w, MGR_Children(tlm)[MGR_NumChildren(tlm) - 1]);
    			if (new_mem != mem)
    			{
			    _XmOptionCallback(new_mem, tlm, NULL);
    			}
    			else
    			{
			    _XmOptionCallback(NULL, tlm, NULL);
    			}
    		}
    	}
    }
    if (tlm && RC_Type(tlm) == XmMENU_OPTION)
    {
	/* rws 30 Apr 1998
	   we need to force the option menu (tlm) to re-calculate its
	   layout based on the new size of its submenu (w)
	 */
    }

    _XmNavigChangeManaged(w);
}

static void
AddPopupHandlers(Widget new_w)
{
    Widget realpar = NULL;

    /* since we're not managed -- we leave that up to the application
     * to get us to pop up, we realize ourselves here. */
    /* XtRealizeWidget(new_w); */

    if (XtIsShell(XtParent(new_w)))
    {
	realpar = XtParent(XtParent(new_w));
    }
    else
    {
	realpar = XtParent(new_w);
    }
    if (realpar == NULL)
    {
	_XmError(new_w, "Can't determine parent of popup menu!\n");
    }

    XtInsertEventHandler(realpar, ButtonPressMask|ButtonReleaseMask,
			 False, _XmPopupButtonPressHandler, (XtPointer)new_w,
			 XtListHead);

    DEBUGOUT(XdbDebug(__FILE__, NULL, "GRAB BUTTON: %p %s %d %x\n",
		      realpar, XtName(realpar),
		      RC_PostButton(new_w), RC_PostModifiers(new_w)));

    XtGrabButton(realpar, RC_PostButton(new_w), RC_PostModifiers(new_w),
		 True, ButtonReleaseMask, GrabModeSync, GrabModeSync,
		 XtWindow(realpar), _XmGetMenuCursorByScreen(XtScreen(new_w)));
}

#ifdef __STDC__
static void
MenuProcEntry(int proc, Widget w,...)
{
    va_list arg_list;
    Display *dpy = XtDisplay(w);
    Widget top_menu;
    Widget *shell;
    Boolean *was_torn;
    XEvent *event;
    extern void _XmTearOffArm();
 
    va_start(arg_list, w);
#else
MenuProcEntry(function, widget, va_alist)
     int function;
     Widget widget;
     va_dcl
{
    va_list arglist;
    Display *dpy = XtDisplay(w);
    Widget top_menu;
    Widget *shell;
    Boolean *was_torn;
    XEvent *event;
    extern void _XmTearOffArm();
 
    va_start(arg_list);
#endif

    switch (proc)
    {
    case XmMENU_BUTTON_POPDOWN:
	/* widget is requesting that the menu it is in be popped down
	 */
	{
	Widget button = w;
	Widget menu = XtParent(button);
	Widget shell;
	Boolean *poppedUp;
	Cardinal num_params = 0;

	    event = va_arg(arg_list, XtPointer);
	    poppedUp = va_arg(arg_list, XtPointer);
	    if (XmIsRowColumn(menu))
	    {
		if (MGR_ActiveChild(menu))
		{
		    _XmMenuDisarmItem(MGR_ActiveChild(menu));
		}
		shell = XtParent(menu);
		if (XmIsMenuShell(shell))
		{
		    if (Shell_PoppedUp(shell))
		    {
			MSClass_PopdownDone(shell)(shell, event, NULL, &num_params);
			*poppedUp = True;
		    }
		    else
		    {
			*poppedUp = False;
		    }
		}
		else
		{
		    if (_XmIsActiveTearOff(menu))
		    {
		    }
		    else
		    {
			_XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_BUTTON_POPDOWN called with button not in a menu shell", __FILE__, __LINE__);
		    }
		    *poppedUp = False;
		}
		/* set the history of menu to button */
		if (!XmIsTearOffButton(button))
		{
		    RC_MemWidget(menu) = button;
		}
		/* if an option menu, change the CascadeButtonGadget label */
		{
		Widget tlm;

		    tlm = RC_LastSelectToplevel(menu);
		    if (tlm && XmIsRowColumn(tlm) && RC_Type(tlm) == XmMENU_OPTION)
		    {
		    	_XmOptionCallback(RC_MemWidget(menu), tlm, NULL);
		    }
		}
	    }
	    else
	    {
		_XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_BUTTON_POPDOWN called with button not in a menu", __FILE__, __LINE__);
		*poppedUp = False;
	    }
	}
	break;

    case XmMENU_PROCESS_TREE:
	break;

    case XmMENU_TRAVERSAL:
	break;

    case XmMENU_SHELL_POPDOWN:
	{
	Widget button = w;
	Widget menu = XtParent(button);
	Widget shell;
	Boolean *poppedUp;
	Cardinal num_params = 0;

	    event = va_arg(arg_list, XtPointer);
	    poppedUp = va_arg(arg_list, XtPointer);
	    if (XmIsRowColumn(menu))
	    {
		if (MGR_ActiveChild(menu) && MGR_ActiveChild(menu) != button)
		{
			_XmMenuDisarmItem(MGR_ActiveChild(menu));
		}
		shell = _XmGetRC_PopupPosted(menu);
		if (shell)
		{
		    if (XmIsMenuShell(shell))
		    {
			if (Shell_PoppedUp(shell))
			{
			    MSClass_PopdownEveryone(shell)(shell, event, NULL, &num_params);
			    *poppedUp = True;
			}
			else
			{
			    *poppedUp = False;
			}
		    }
		    else
		    {
			if (XtIsTransientShell(shell) || _XmIsActiveTearOff(menu))
			{
			}
			else
			{
			    _XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_SHELL_POPDOWN called with button not in a menu shell %s %s", __FILE__, __LINE__, XtName(menu), XtName(shell));
			}
			*poppedUp = False;
		    }
		}
		else
		{
		    /* nothing popped up */
		    *poppedUp = False;
		}
	    }
	    else
	    {
		_XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_SHELL_POPDOWN called with button not in a menu", __FILE__, __LINE__);
		*poppedUp = False;
	    }
	}
	break;

    case XmMENU_CALLBACK:
	break;

    case XmMENU_BUTTON:
	/* widget got a button event, verify that it is a valid button for
	   this type of menu
	 */
	{
	Widget button = w;
	Widget menu = XtParent(button);
	XButtonEvent *xbe;
	Boolean *validButton;
	Widget tlm;

	    event = va_arg(arg_list, XtPointer);
	    validButton = va_arg(arg_list, XtPointer);
	    if (event && (event->type == ButtonPress || event->type == ButtonRelease))
	    {
		xbe = &(event->xbutton);
		if (XmIsRowColumn(menu))
		{
		    _XmGetActiveTopLevelMenu(menu, &tlm);
		    if (tlm && XmIsRowColumn(tlm))
		    {
			switch(RC_Type(tlm))
			{
			case XmMENU_BAR:
			case XmMENU_PULLDOWN:
			case XmMENU_OPTION:
			    *validButton = (xbe->button == 1);
			    break;
			case XmMENU_POPUP:
			    *validButton = ((xbe->button == 1) ||
					    (xbe->button == 3));
			    break;
			default:
			    _XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_BUTTON do not know the type of TopLevelMenu %s", __FILE__, __LINE__,XtName(tlm));
			    *validButton = False;
			    break;
			}
		    }
		    else
		    {
			_XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_BUTTON could not find TopLevelMenu", __FILE__, __LINE__);
			*validButton = False;
		    }
		}
		else
		{
		    _XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_BUTTON called by widget without RC parent", __FILE__, __LINE__);
		    *validButton = False;
		}
	    }
	    else
	    {
		_XmWarning(w, "%s(%d) - RCClass_MenuProcs XmMENU_BUTTON called with non button event", __FILE__, __LINE__);
		*validButton = False;
	    }
	}
	break;

    case XmMENU_CASCADING:
	{
	Widget cb = w;
	Widget sub_pane;
	Widget shell;
	Dimension shadow;
	Position my_x, my_y;

	    /* FIX ME: lots of this should move to MenuShell:manage_child */
	    event = va_arg(arg_list, XtPointer);
	    sub_pane = XmIsGadget(cb) ? CBG_Submenu(cb) : CB_Submenu(cb);

	    DEBUGOUT(XdbDebug(__FILE__, cb, "MenuProcEntry() - XmMENU_CASCADING\n"));
	    if (!sub_pane)
	    {
		DEBUGOUT(XdbDebug(__FILE__, cb, "Cascading Popup: no sub pane\n"));

		return;
	    }
	    {
	    Widget shell;
	    Boolean was_torn;

		RCClass_MenuProcs(XtClass(sub_pane))(XmMENU_RESTORE_TEAROFF_TO_MENUSHELL,
					     sub_pane, &shell, &was_torn, event);
	    }

	    /* FIX ME: if shared menu shell, configure object, ordinary popup */

	    shell = XtParent(sub_pane);

	    /* Register inside the RC that this cascadebutton is the one that 
	     * triggered the menu.
	     */
	    RC_CascadeBtn(sub_pane) = cb;

	    /* position the row column inside the menushell */
	    _XmMoveObject(sub_pane, 0, 0);

	    /* now move the menushell */
	    /* rws 21 Dec 1997
	       If the is a tear off it is possible that it has been re-parented
	       a few times.  This seems to mess up where Xt thinks the cascade
	       button is. Therefore we must suffer the round trip server request
	       to make sure that we get the correct position.
	     */
	    if (!_XmIsActiveTearOff(XtParent(cb)))
	    {
		XtTranslateCoords(cb, 0, 0, &my_x, &my_y);
	    }
	    else
	    {
	    Window child;
	    int x,y;

		XTranslateCoordinates(XtDisplay(cb),
			XtWindow(cb),
			RootWindowOfScreen(XtScreen(cb)),
			0, 0,
			&x, &y,
			&child);
		my_x = x; my_y = y;
	    }

	    /* FIX ME */
	    switch (RC_Type(XtParent(cb)))
	    {
	    case XmMENU_BAR:

		if (my_x + XtWidth(sub_pane) >= WidthOfScreen(XtScreen(cb)))
		{
		    /* try to fit it on the screen.  But don't make it go off
		     * the left side! */
		    my_x += (Position)WidthOfScreen(XtScreen(cb)) -
			(Position)(my_x + XtWidth(sub_pane));
		}
		if (my_x < 0)
		{
		    my_x = 0;
		}

		if (my_y + XtHeight(cb) + XtHeight(sub_pane)
		    >= HeightOfScreen(XtScreen(cb)) && my_y - XtHeight(sub_pane) >= 0)
		{
		    /* try to fit it on the screen.  But don't make it go off
		     * the top side! */
		    my_y -= XtHeight(sub_pane);
		}
		else
		{
		    my_y += XtHeight(cb);
		}

		_XmMoveObject(shell, my_x, my_y);

		break;

	    case XmMENU_POPUP:
	    case XmMENU_PULLDOWN:
		shadow = XmIsGadget(cb) ? LabG_Shadow(cb) : Lab_Shadow(cb);

		DEBUGOUT(XdbDebug(__FILE__, cb, "MenuProcEntry() - XmMENU_CASCADING - popup/pulldown %d %d\n",
			my_x, my_y));
		if (my_x + XtWidth(cb) - shadow + XtWidth(sub_pane)
		    >= WidthOfScreen(XtScreen(cb)) &&
		    my_x + shadow - XtWidth(sub_pane) >= 0)
		{
		    /* try to fit it on the screen.  But don't make it go off
		     * the left side! */
		    my_x -= XtWidth(sub_pane) - shadow;
		}
		else
		{
		    my_x += XtWidth(cb) - shadow;
		}

		if (my_y + XtHeight(sub_pane) >= HeightOfScreen(XtScreen(cb)))
		{
		    /* try to fit it on the screen.  But don't make it go off
		     * the top side! */
		    my_y += (Position)HeightOfScreen(XtScreen(cb)) -
			(Position)(my_y + XtHeight(sub_pane));
		}
		if (my_y < 0)
		{
		    my_y = 0;
		}

		_XmMoveObject(shell, my_x, my_y);

		break;

	    case XmMENU_OPTION:
		if (RC_MemWidget(XtParent(cb)))
		{
		    if (my_x + XtWidth(sub_pane) >= WidthOfScreen(XtScreen(cb)))
		    {
			/* try to fit it on the screen.  But don't make it go off
			 * the left side! */
			my_x += (Position)WidthOfScreen(XtScreen(cb)) -
			    (Position)(my_x + XtWidth(sub_pane));
		    }
		    if (my_x < 0)
		    {
			my_x = 0;
		    }

		    my_y -= XtY(RC_MemWidget(XtParent(cb)));

		    if (my_y + XtHeight(sub_pane) >= HeightOfScreen(XtScreen(cb)))
		    {
			/* try to fit it on the screen.  But don't make it go off
			 * the top side! */
			my_y += (Position)HeightOfScreen(XtScreen(cb)) -
			    (Position)(my_y + XtHeight(sub_pane));
		    }
		    if (my_y < 0)
		    {
			my_y = 0;
		    }

		    DEBUGOUT(XdbDebug(__FILE__, cb, "MenuProcEntry() - XmMENU_CASCADING - Moving OPTION menu to %dx%d\n",my_x,my_y));
		    _XmMoveObject(shell, my_x, my_y);
		}
		else
		    DEBUGOUT(XdbDebug(__FILE__, shell, "Not moving\n"));
		break;

	    default:
		/* FIX ME */
		return;
		break;
	    }

	    RC_PopupPosted(XtParent(cb)) = sub_pane;
	    DEBUGOUT(XdbDebug(__FILE__, cb, "%s posted by %s top %s\n",
			XtName(sub_pane),
			XtName(XtParent(cb)),
			RC_LastSelectToplevel(XtParent(cb)) ? XtName(RC_LastSelectToplevel(XtParent(cb))) : "NULL"));

	    RC_LastSelectToplevel(sub_pane) = RC_LastSelectToplevel(XtParent(cb));
	    MGR_ActiveChild(XtParent(cb)) = cb;
	    Lab_MenuArm(cb);

	    /* This private shell stuff should be hidden in MenuShell somewhere
	       Nothing but MenuShell needs to know anything about private shells!
	     */
	    if (!MS_PrivateShell(shell))
	    {
		XtManageChild(sub_pane);
		/* rws 13 Mar 1997
		   Not too sure about this yet so keep it out for now.
		XAllowEvents(XtDisplay(sub_pane), SyncPointer, CurrentTime);
 
		_XmAddGrab(shell, False, False);
		*/
	    }
	    else
	    {
		MSClass_PopupSharedMenuPane(shell)(shell, sub_pane, event);
	    }
	}
	break;

    case XmMENU_SUBMENU:
	{
	Widget button = w;
	Widget submenu = XmIsGadget(w) ? CBG_Submenu(w) : CB_Submenu(w);

	    if (RC_Type(XtParent(w)) == XmMENU_OPTION &&
		submenu != NULL && XmIsRowColumn(submenu))
	    {
		RC_CascadeBtn(submenu) = button;
		RC_OptionSubMenu(XtParent(w)) = submenu;
		/* rws 5 May 1998
		   should be setting RC_LastSelectTopLevel(submenu) = XtParent(button);
		   I think.
		 */

		if (XmIsGadget(w))
		{
		    _XmFixOptionMenu(XtParent(w), False);
		}
		else
		{
		    _XmFixOptionMenu(XtParent(w), True);
		}
	    }
	}
	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, True,
			GrabModeSync, GrabModeSync,
			CurrentTime);

	/* 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);

	DEBUGOUT(XdbDebug(__FILE__, w, "RC FOCUS SET: %s\n", XtName(w)));

	_XmMenuFocus(w, XmMENU_FOCUS_SET, CurrentTime);

	XAllowEvents(dpy, AsyncKeyboard, CurrentTime);

	_XmAddGrab(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,
		       _XmGetMenuCursorByScreen(XtScreen(w)),
		       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);

	_XmRemoveGrab(w);

	DEBUGOUT(XdbDebug(__FILE__, w, "RC RESTORE: %s\n", XtName(w)));

        _XmMenuFocus(w, XmMENU_FOCUS_RESTORE, CurrentTime);

	RC_SetArmed(w, False);

	break;

    case XmMENU_BAR_CLEANUP:
	top_menu = RC_PopupPosted(w);

	/* Make sure a valid menu was found */
	if (top_menu && XmIsRowColumn(top_menu) &&
	    (RC_Type(top_menu) != XmWORK_AREA) &&
	    (RC_Type(top_menu) != XmMENU_OPTION))
	{
	    /* Release the keyboard and pointer grabs */
	    _XmUngrabKeyboard(w, CurrentTime);
	    _XmUngrabPointer(w, CurrentTime);
 
	    DEBUGOUT(XdbDebug(__FILE__, w,
			      "   Doing MenuShellPopdownDone(%s)\n",
			      XtName(XtParent(top_menu))));
 
	    MSClass_PopdownDone(XtParent(top_menu))(XtParent(top_menu), NULL,
						    NULL, NULL);
	}
	else
	{
	    _XmWarning(w, "CascadeButton's parent is not a valid menu widget");
	}
	break;

    case XmMENU_STATUS:
	break;

    case XmMENU_MEMWIDGET_UPDATE:
	/* rws 5 May 1998
	   this could call _XmFixOptionMenu
	 */
	break;

    case XmMENU_POPDOWN:
	break;

    case XmMENU_RESTORE_EXCLUDED_TEAROFF_TO_TOPLEVEL_SHELL:
	event = va_arg(arg_list, XEvent *);
	_XmRestoreExcludedTearOffToToplevelShell(w, event);
	break;

    case XmMENU_RESTORE_TEAROFF_TO_TOPLEVEL_SHELL:
	/* fix up RC_LastSelectTopLevel and RC_CascadeBtn */
	event = va_arg(arg_list, XEvent *);
	_XmRestoreTearOffToToplevelShell(w, event);
	break;

    case XmMENU_RESTORE_TEAROFF_TO_MENUSHELL:
	shell = va_arg(arg_list, Widget *);
	was_torn = va_arg(arg_list, Boolean *);
	event = va_arg(arg_list, XEvent *);

	/* fix up RC_LastSelectTopLevel and RC_CascadeBtn */
	if (RC_TearOffModel(w) == XmTEAR_OFF_ENABLED)
	{
	    DEBUGOUT(XdbDebug(__FILE__, w,
			      "restoring tear off menu to menu shell\n"));
 
	    if (RC_TornOff(w))
	    {
		*was_torn = True;
	    }
 
	    _XmRestoreTearOffToMenuShell(w, event);
 
	    *shell = XtParent(w);
	}
	break;

    case XmMENU_GET_LAST_SELECT_TOPLEVEL:
	break;

    case XmMENU_TEAR_OFF_ARM:
	_XmTearOffArm(w);
	break;

    default:
	break;
    }

    va_end(arg_list);
}

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

/* rws add callbacks to sub menu */
static 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))
    {
#ifdef TEST29
	RC_OptionSubMenu(RC_OptionSubMenu(new_w)) = new_w;
#endif
#if 0
	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);
	    }
	}
#endif

	/* 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)))
	    {

		if (XmIsTearOffButton(MGR_Children(RC_OptionSubMenu(new_w))[0]))
		{
		    if (MGR_NumChildren(RC_OptionSubMenu(new_w)) > 2)
		    {
			RC_MemWidget(new_w) =
			    MGR_Children(RC_OptionSubMenu(new_w))[1];
		    }
		}
		else
		{
		    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;

    if (w)
    {
	XtVaGetValues(w, XmNlabelString, &ButtonLabel,
		      NULL);
    }
    else
    {
    	ButtonLabel = XmStringCreateSimple("");
    }
    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 cnt 0 widget -> True\n"));
#if 0
		_XmToggleButtonSetState(w, True);
#else
		XmToggleButtonSetState(w, True, True);
		cbs->set = True;
#endif
	    }
	    else if (XmIsToggleButtonGadget(w))
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, w,
			"_XmRadioCallback: toggle cnt 0 gadget -> True\n"));
#if 0
		_XmToggleButtonGadgetSetState(w, True);
#else
		XmToggleButtonGadgetSetState(w, True, True);
		cbs->set = True;
#endif
	    }

	    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 widget -> False\n"));
		XmToggleButtonSetState(tgl, False, True);
	    }
	    else if (w == tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle widget -> True\n"));
		_XmToggleButtonSetState(tgl, True);
	    }
	}
	else if (XmIsToggleButtonGadget(tgl) &&
		 XmToggleButtonGadgetGetState(w))
	{
	    if (w != tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle gadget -> False\n"));
		XmToggleButtonGadgetSetState(tgl, False, True);
	    }
	    else if (w == tgl && cbs && cbs->set)
	    {
		DEBUGOUT(XdbDebug2(__FILE__, rc, tgl,
			"_XmRadioCallback: toggle gadget -> True\n"));
		_XmToggleButtonGadgetSetState(tgl, True);
	    }
	}
    }
}

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

    if (RC_Entry_cb(rc))
    {
	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))));
    }

#ifndef ALWAYS_INSTALL_ENTRY_CALLBACK 
    if (RC_Entry_cb(rc))
    {
#endif
	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))
	    {
		XtRemoveCallbacks(w, XmNvalueChangedCallback,
				  TB_ValueChangedCallback(w));
	    }
	    XtAddCallback(w, XmNvalueChangedCallback, _XmEntryCallback, rc);
	}
	else if (XmIsToggleButtonGadget(w))
	{
	    if (TBG_ValueChangedCallback(w))
	    {
		XtRemoveCallbacks(w, XmNvalueChangedCallback,
				  TBG_ValueChangedCallback(w));
	    }
	    XtAddCallback(w, XmNvalueChangedCallback, _XmEntryCallback, rc);
	}
#ifndef ALWAYS_INSTALL_ENTRY_CALLBACK
    }
#endif

    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: %d %d\n",
		      RCC_MarginTop(new_w),
		      RCC_MarginBottom(new_w)));

#ifdef TEST29
    if (RC_OptionSubMenu(rc))
    {
	if (RC_Type(RC_OptionSubMenu(rc)) == XmMENU_OPTION)
	{
	    if(RC_MemWidget(RC_OptionSubMenu(rc)) == new_w)
	    {
		_XmOptionCallback(new_w, RC_OptionSubMenu(rc), NULL);
	    }
	}
    }
#endif
    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;
    }

    DEBUGOUT(XdbDebug(__FILE__, new_w, "constraint_set_values (end): %d %d\n",
		      RCC_MarginTop(new_w),
		      RCC_MarginBottom(new_w)));

    return refresh_needed;
}

static XmNavigability
widget_navigable(Widget w)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "%s(%d):widget_navigable\n", __FILE__, __LINE__));
    DEBUGOUT(XdbDebug(__FILE__, w, "    Sensitive      %s\n", XdbBoolean2String(XtSensitive(w))));
    DEBUGOUT(XdbDebug(__FILE__, w, "    TraversalOn    %s\n", XdbBoolean2String(MGR_TraversalOn(w))));
    DEBUGOUT(XdbDebug(__FILE__, w, "    RC_Type        %s\n", XdbRcType2String(RC_Type(w))));
    DEBUGOUT(XdbDebug(__FILE__, w, "    DragMode       %s\n", XdbBoolean2String(_XmGetInDragMode(w))));
    DEBUGOUT(XdbDebug(__FILE__, w, "    RC_PopupPosted %s\n", 
    	RC_PopupPosted(w) ? XtName(RC_PopupPosted(w)) : "NULL" ));
    DEBUGOUT(XdbDebug(__FILE__, w, "    NavType        %s\n", XdbNavigationType2String(MGR_NavigationType(w))));
    if (XtSensitive(w) && MGR_TraversalOn(w) &&
	(((RC_Type(w) == XmWORK_AREA || RC_Type(w) == XmMENU_OPTION)) ||
        ((RC_Type(w) == XmMENU_PULLDOWN || RC_Type(w) == XmMENU_POPUP) && !_XmGetInDragMode(w)) ||
        (RC_Type(w) == XmMENU_BAR && !_XmGetInDragMode(w) && RC_PopupPosted(w))))
    {
	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
DoBtnEventCleanupReplay(Widget w, XEvent *event,
			String *params, Cardinal *num_params)
{
    Widget menu_shell;
    Widget tlrc;

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

    _XmGetActiveTopLevelMenu(w, &tlrc);  /* this is RC_LastSelectToplevel() no?? */

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

    menu_shell = XtParent(tlrc);

    if (XmIsMenuShell(menu_shell))
    {
    DEBUGOUT(XdbDebug(__FILE__, w,
		   "DoBtnEventCleanupReplay: calling MenuShellPopdownDone\n"));
    XtCallActionProc(menu_shell, "MenuShellPopdownDone",
		     event, params, *num_params);
    }
    else if (_XmIsActiveTearOff(tlrc))
    {
    Boolean poppedUp;

	/* should use RC_CascadeBtn(RC_PopupPosted(tlrc)) I think.
	   MGR_ActiveChild is really only for the active Gadget.
	 */
	RC_MenuShellPopdown(MGR_ActiveChild(tlrc), event, &poppedUp);
    }

    _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);
}

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

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmMenuBtnDown\n"));
    /* 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,
			  "HEY1, 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"));
    }
}

void
_XmMenuBtnUp(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,
		       "HEY2, Got ButtonRelease event for the second time!\n"));

	return;
    }

    /*
     * If event was in a child gadget, then activate 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)
	{
            Widget shell = XtParent(RC_PopupPosted(w));
 
	    if (MGR_ActiveChild(w))
	    {
		_XmMenuDisarmItem(MGR_ActiveChild(w));
	    }
            /* This PrivateShell stuff should be in MenuShell somewhere.
               RC should just be able to bring the menu down and let MenuShell
               worry about the details of how to do this.
             */
            if (shell && XmIsMenuShell(shell) && MS_PrivateShell(shell))
            {
                XtCallActionProc(shell, "XtMenuPopdown",
                                 event, params, *num_params);
		RC_PopupPosted(w) = NULL;
            }
            else
            {
                if (!RC_TornOff(RC_PopupPosted(w)))
                {
		    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
MenuBarGadgetSelect(Widget w, XEvent *event,
		    String *params, Cardinal *num_params)
{
    DEBUGOUT(XdbDebug(__FILE__, w, "MenuBarGadgetSelect()\n"));
}

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

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

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

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

/*
 * most of these are already written under different names
 */
void
_XmPostPopupMenu(Widget wid, XEvent *event)
{
    XmMenuState state = _XmGetMenuState(wid);
    int type = event->type;
    Time time;

    DEBUGOUT(XdbDebug(__FILE__, wid, "PostPopupMenu()\n"));

    time = XtLastTimestampProcessed(XtDisplay(wid));
    if (type == 0)
    {
	type = KeyPress;
	/* rws 2 Apr 1998
	   This makes the popup's in ddd and Mozilla work but, the real
	   problem is the GrabButton is not getting called for some reason.
	   The grab is placed on the RC in AddPopupHandlers but it never
	   gets triggered?????
	 */
	type = ButtonPress;
    }

    state->RC_ButtonEventStatus.waiting_to_be_managed = False;
    state->RC_ButtonEventStatus.time = time;

    if (!XmIsRowColumn(wid) || RC_Type(wid) != XmMENU_POPUP)
    {
	_XmWarning(wid, "_XmPostPopupMenu sent non rowcolumn widget\n");

	return;
    }

    if (type == KeyPress || type == KeyRelease)
    {
	_XmSetInDragMode(wid, False);
    }
    else
    {
	_XmSetInDragMode(wid, True);
    }
    _XmMenuSetInPMMode(wid, True);

    if (event->type == ButtonRelease)
    {
	RCClass_MenuProcs(XtClass(wid))(XmMENU_ARM, wid, NULL);
    }

    /* rws 7 May 1998
       Mozilla's Bookmark, Forward, Back button menus do not post without
       this XtManageChild().
     */
    XtManageChild(wid);
    XtCallActionProc(XtParent(wid), "XtMenuPopup", event, NULL, 0);

    RC_SetArmed(wid, True);

    RC_CascadeBtn(wid) = NULL;
}

void
_XmSetPopupMenuClick(Widget wid,
		     Boolean popupMenuClick)
{
    RC_PopupMenuClick(wid) = True;
}

Boolean
_XmGetPopupMenuClick(Widget wid)
{
    return RC_PopupMenuClick(wid);
}

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;

    DEBUGOUT(XdbDebug(__FILE__, w, "_XmMenuFocus()\n"));
    /* 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);

	XmProcessTraversal(state->RC_menuFocus.oldWidget, XmTRAVERSE_CURRENT);

	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);

	XtSetKeyboardFocus(w, w);

	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;

    DEBUGOUT(XdbDebug(__FILE__, wid, "_XmGetActiveTopLevelMenu()\n"));
    /* find the topmost menu pane */
    if ((toplevelrc = RC_LastSelectToplevel(wid)))
    {
	/* Pulldown and option menus keep track over their toplevel
	 * RowColumn...
	 */
	Widget top_pane;

	DEBUGOUT(XdbDebug(__FILE__, wid, "_XmGetActiveTopLevelMenu() - RC_LastSelectTopLevel %s\n",
		XtName(toplevelrc)));
	if ((top_pane = RC_PopupPosted(toplevelrc)))
	{
	    toplevelrc = top_pane;
	    DEBUGOUT(XdbDebug(__FILE__, wid, "_XmGetActiveTopLevelMenu() - RC_PopupPosted %s\n",
		XtName(toplevelrc)));
	}
	else
	{
	    if (_XmIsActiveTearOff(wid))
	    {
	    	toplevelrc = wid;
	    }
	    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);
	}
    }

    DEBUGOUT(XdbDebug(__FILE__, wid, "_XmGetActiveTopLevelMenu() - returning %s\n",
		toplevelrc ? XtName(toplevelrc) : "NULL" ));
    *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
_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)
{
    _XmWarning(w, "%s(%d) - _XmMenuPopDown() not implemented ", __FILE__, __LINE__);
}

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. */
    unsigned int button = 0;
    int type = 0;
    unsigned int modifiers = 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;
    }

    if (_XmMapBtnEvent(menuPost, &type, &button, &modifiers))
    {
	*value = (XtArgVal)menuPost;

	/* does this one ever change? */
	RC_PostEventType(widget) = type;
	RC_PostButton(widget) = button;
	RC_PostModifiers(widget) = modifiers;

	if (RC_Type(widget) == XmMENU_POPUP && type == ButtonRelease)
	{
	    _XmSetPopupMenuClick(widget, True);
	}
	else
	{
	    _XmSetPopupMenuClick(widget, False);
	}

	return XmSYNTHETIC_LOAD;
    }
    else
    {
	return XmSYNTHETIC_NONE;
    }
}

static void
_XmPopupButtonPressHandler(Widget w, XtPointer client_data,
			   XEvent *event, Boolean *cont)
{
    Widget rc = (Widget)client_data;
    XmMenuState state = _XmGetMenuState(w);

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "BUTTON PRESS %p %s %p %s\n",
		      w, XtName(w), rc, XtName(rc)));
#if 0
    printf("BUTTON PRESS %p %s %p %s\n",
		      w, XtName(w), rc, XtName(rc));
#endif
    /* first check if the event is valid wrt our menupost resource */
    if (event->xany.type != RC_PostEventType(rc) ||
	event->xbutton.button != RC_PostButton(rc) ||
        event->xbutton.state != RC_PostModifiers(rc))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "Not post button. %d %d Button %d PF %d\n",
			  event->xany.type, ButtonPress,
			  event->xbutton.button, RC_PostButton(rc)));
	XtUngrabPointer(w,CurrentTime);
	XtUngrabKeyboard(w,CurrentTime);
	return;
    }

    /* if we're already waiting to be managed, do nothing. */
    if (state->RC_ButtonEventStatus.waiting_to_be_managed)
    {
	DEBUGOUT(XdbDebug(__FILE__, w, "Waiting to be managed\n"));
	XtUngrabPointer(w,CurrentTime);
	XtUngrabKeyboard(w,CurrentTime);
	return;
    }

    DEBUGOUT(XdbDebug(__FILE__, rc, "  Filling in ButtonEventStatusRec\n"));
    DEBUGOUT(XdbDebug(__FILE__, rc,
		      "  Event: win %08x subwin: %08x time: %d ser: %d\n",
		      event->xbutton.window, event->xbutton.subwindow,
		      event->xbutton.time, event->xbutton.serial));
    DEBUGOUT(XdbDebug(__FILE__, rc,
		      "         x_root %d y_root: %d x: %d y: %d "
		      "state: %d button: %d\n",
		      event->xbutton.x_root, event->xbutton.y_root,
		      event->xbutton.x, event->xbutton.y,
		      event->xbutton.state, event->xbutton.button));

    state->RC_ButtonEventStatus.waiting_to_be_managed = True;
    state->RC_ButtonEventStatus.event = event->xbutton;
    state->RC_ButtonEventStatus.time = event->xbutton.time;
    state->RC_ButtonEventStatus.verified = True; /* Is it really? FIX ME */
	XtUngrabPointer(w,CurrentTime);
	XtUngrabKeyboard(w,CurrentTime);
}

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;
}

#if 0
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;
}
#endif

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

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

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

