/**
 *
 * $Id: Manager.c,v 1.49 1998/04/16 21:46:44 u27113 Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static char rcsid[] = "$Id: Manager.c,v 1.49 1998/04/16 21:46:44 u27113 Exp $";

#include <LTconfig.h>

#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif

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

#include <Xm/XmP.h>
#include <Xm/BaseClassP.h>
#include <Xm/ManagerP.h>
#include <Xm/GadgetP.h>
#include <Xm/RepType.h>
#include <Xm/TransltnsP.h>
#include <X11/keysym.h>
#include <X11/Xfuncs.h>
#include <Xm/VirtKeysP.h>

#include <XmI/DebugUtil.h>

/* For determining class type */
#include <Xm/CascadeBP.h>
#include <Xm/CascadeBGP.h>
#include <Xm/MenuUtilP.h>

/*
 * Yes I know this is crazy... Danny
 */
#include <Xm/RowColumnP.h>
#include <Xm/DialogS.h>

/* 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 realize(Widget w, XtValueMask *value_mask,
		    XSetWindowAttributes *attributes);

static void destroy(Widget w);

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 changed_managed(Widget w);

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

static XmNavigability widget_navigable(Widget w);

void _XmManagerInstallAccelerator(Widget m, Widget w, String s);

/* action routine prototypes */
void _XmGadgetButtonMotion(Widget w, XEvent *event,
			   String *params, Cardinal *num_params);

void _XmGadgetArm(Widget w, XEvent *event,
		  String *params, Cardinal *num_params);

void _XmGadgetActivate(Widget w, XEvent *event,
		       String *params, Cardinal *num_params);

void _XmGadgetMultiArm(Widget w, XEvent *event,
		       String *params, Cardinal *num_params);

void _XmGadgetMultiActivate(Widget w, XEvent *event,
			    String *params, Cardinal *num_params);

void _XmGadgetDrag(Widget w, XEvent *event,
		   String *params, Cardinal *num_params);

void _XmGadgetSelect(Widget w, XEvent *event,
		     String *params, Cardinal *num_params);

void _XmManagerParentActivate(Widget w, XEvent *event,
			      String *params, Cardinal *num_params);

void _XmManagerParentCancel(Widget w, XEvent *event,
			    String *params, Cardinal *num_params);

void _XmGadgetTraversePrevTabGroup(Widget w, XEvent *event,
				   String *params, Cardinal *num_params);

void _XmGadgetTraverseNextTabGroup(Widget w, XEvent *event,
				   String *params, Cardinal *num_params);

void _XmGadgetTraversePrev(Widget w, XEvent *event,
			   String *params, Cardinal *num_params);

void _XmGadgetTraverseNext(Widget w, XEvent *event,
			   String *params, Cardinal *num_params);

void _XmGadgetTraverseUp(Widget w, XEvent *event,
			 String *params, Cardinal *num_params);

void _XmGadgetTraverseDown(Widget w, XEvent *event,
			   String *params, Cardinal *num_params);

void _XmGadgetTraverseLeft(Widget w, XEvent *event,
			   String *params, Cardinal *num_params);

void _XmGadgetTraverseRight(Widget w, XEvent *event,
			    String *params, Cardinal *num_params);

void _XmGadgetTraverseHome(Widget w, XEvent *event,
			   String *params, Cardinal *num_params);

void _XmGadgetHelp(Widget w, XEvent *event,
		   String *params, Cardinal *num_params);

void _XmGadgetKeyInput(Widget w, XEvent *event,
		       String *params, Cardinal *num_params);

/*
 * the event handler to handle pointer position related events for gadget
 * children
 */
static void _XmManagerEventHandler(Widget w, XtPointer data,
				   XEvent *event, Boolean *cont);

static XtActionsRec actions[] =
{
    {"ManagerEnter", _XmManagerEnter},
    {"ManagerLeave", _XmManagerLeave},
    {"ManagerFocusIn", _XmManagerFocusIn},
    {"ManagerFocusOut", _XmManagerFocusOut},
    {"ManagerGadgetPrevTabGroup", _XmGadgetTraversePrevTabGroup},
    {"ManagerGadgetNextTabGroup", _XmGadgetTraverseNextTabGroup},
    {"ManagerGadgetTraversePrev", _XmGadgetTraversePrev},
    {"ManagerGadgetTraverseNext", _XmGadgetTraverseNext},
    {"ManagerGadgetTraverseLeft", _XmGadgetTraverseLeft},
    {"ManagerGadgetTraverseRight", _XmGadgetTraverseRight},
    {"ManagerGadgetTraverseUp", _XmGadgetTraverseUp},
    {"ManagerGadgetTraverseDown", _XmGadgetTraverseDown},
    {"ManagerGadgetTraverseHome", _XmGadgetTraverseHome},
    {"ManagerGadgetSelect", _XmGadgetSelect},
    {"ManagerParentActivate", _XmManagerParentActivate},
    {"ManagerParentCancel", _XmManagerParentCancel},
    {"ManagerGadgetButtonMotion", _XmGadgetButtonMotion},
    {"ManagerGadgetKeyInput", _XmGadgetKeyInput},
    {"ManagerGadgetHelp", _XmGadgetHelp},
    {"ManagerGadgetArm", _XmGadgetArm},
    {"ManagerGadgetDrag", _XmGadgetDrag},
    {"ManagerGadgetActivate", _XmGadgetActivate},
    {"ManagerGadgetMultiArm", _XmGadgetMultiArm},
    {"ManagerGadgetMultiActivate", _XmGadgetMultiActivate},
    {"Enter", _XmManagerEnter},
    {"FocusIn", _XmManagerFocusIn},
    {"Help", _XmGadgetHelp},
    {"Arm", _XmGadgetArm},
    {"Activate", _XmGadgetActivate},

    {"ManagerGadgetMultiArm", _XmGadgetMultiArm},
};

#define Offset(field) XtOffsetOf(XmManagerRec, manager.field)

/* Resources for the manager class */
static XtResource resources[] =
{
    {
	XmNunitType, XmCUnitType, XmRUnitType,
	sizeof(unsigned char), Offset(unit_type),
	XmRCallProc, (XtPointer)_XmUnitTypeDefault
    },
    {
	XmNx, XmCPosition, XmRHorizontalPosition,
	sizeof(Position), XtOffsetOf(XmManagerRec, core.x),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNy, XmCPosition, XmRVerticalPosition,
	sizeof(Position), XtOffsetOf(XmManagerRec, core.y),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNwidth, XmCDimension, XmRHorizontalDimension,
	sizeof(Dimension), XtOffsetOf(XmManagerRec, core.width),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNheight, XmCDimension, XmRVerticalDimension,
	sizeof(Dimension), XtOffsetOf(XmManagerRec, core.height),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNborderWidth, XmCBorderWidth, XmRHorizontalDimension,
	sizeof(Dimension), XtOffsetOf(XmManagerRec, core.border_width),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNforeground, XmCForeground, XmRPixel,
	sizeof(Pixel), Offset(foreground),
	XmRCallProc, (XtPointer)_XmForegroundColorDefault
    },
    {
	XmNbackground, XmCBackground, XmRPixel,
	sizeof(Pixel), XtOffsetOf(XmManagerRec, core.background_pixel),
	XmRCallProc, (XtPointer)_XmBackgroundColorDefault
    },
    {
	XmNbackgroundPixmap, XmCPixmap, XmRXmBackgroundPixmap,
	sizeof(Pixmap), XtOffsetOf(XmManagerRec, core.background_pixmap),
	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
    },
    {
	XmNhighlightColor, XmCHighlightColor, XmRPixel,
	sizeof(Pixel), Offset(highlight_color),
	XmRCallProc, (XtPointer)_XmHighlightColorDefault
    },
    {
	XmNhighlightPixmap, XmCHighlightPixmap, XmRManHighlightPixmap,
	sizeof(Pixmap), Offset(highlight_pixmap),
	XmRCallProc, (XtPointer)_XmManagerHighlightPixmapDefault
    },
    {
	XmNnavigationType, XmCNavigationType, XmRNavigationType,
	sizeof(XmNavigationType), Offset(navigation_type),
	XmRImmediate, (XtPointer)XmTAB_GROUP
    },
    {
	XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
	sizeof(Dimension), Offset(shadow_thickness),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNtopShadowColor, XmCTopShadowColor, XmRPixel,
	sizeof(Pixel), Offset(top_shadow_color),
	XmRCallProc, (XtPointer)_XmTopShadowColorDefault
    },
    {
	XmNtopShadowPixmap, XmCTopShadowPixmap, XmRManTopShadowPixmap,
	sizeof(Pixmap), Offset(top_shadow_pixmap),
	XmRCallProc, (XtPointer)_XmManagerTopShadowPixmapDefault
    },
    {
	XmNbottomShadowColor, XmCBottomShadowColor, XmRPixel,
	sizeof(Pixel), Offset(bottom_shadow_color),
	XmRCallProc, (XtPointer)_XmBottomShadowColorDefault
    },
    {
	XmNbottomShadowPixmap, XmCBottomShadowPixmap, XmRManBottomShadowPixmap,
	sizeof(Pixmap), Offset(bottom_shadow_pixmap),
	XtRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
    },
    {
	XmNhelpCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(help_callback),
	XtRPointer, (XtPointer)NULL
    },
    {
	XmNuserData, XmCUserData, XmRPointer,
	sizeof(XtPointer), Offset(user_data),
	XmRPointer, (XtPointer)NULL
    },
    {
	XmNtraversalOn, XmCTraversalOn, XmRBoolean,
	sizeof(Boolean), Offset(traversal_on),
	XmRImmediate, (XtPointer)True
    },
    {
	XmNstringDirection, XmCStringDirection, XmRStringDirection,
	sizeof(XmStringDirection), Offset(string_direction),
	XmRImmediate, (XtPointer)((XmStringDirection)XmUNSPECIFIED)
    },
    {
	XmNinitialFocus, XmCInitialFocus, XmRWidget,
	sizeof(Widget), Offset(initial_focus),
	XmRImmediate, (XtPointer)NULL
    }
};

#define MOffset(field)	XtOffset(XmManagerWidget, manager.field)
#define COffset(field)	XtOffset(XmManagerWidget, core.field)
static XmSyntheticResource syn_resources[] =
{
    /* core part */
    {
	XmNx,
	sizeof(Position), COffset(x),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    {
	XmNy,
	sizeof(Position),
	COffset(y),
	_XmFromVerticalPixels, _XmToVerticalPixels
    },
    {
	XmNwidth,
	sizeof(Dimension), COffset(width),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    {
	XmNheight,
	sizeof(Dimension), COffset(height),
	_XmFromVerticalPixels, _XmToVerticalPixels
    },
    {
	XmNborderWidth,
	sizeof(Dimension), COffset(border_width),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    /* manager */
    {
	XmNshadowThickness,
	sizeof(Dimension), MOffset(shadow_thickness),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
};
/* *INDENT-OFF* */
static XmBaseClassExtRec _XmManagerCoreClassExtRec = {
    /* next_extension            */ NULL,
    /* record_type               */ NULLQUARK,                             
    /* version                   */ XmBaseClassExtVersion,
    /* size                      */ sizeof(XmBaseClassExtRec),
    /* initialize_prehook        */ NULL,
    /* set_values_prehook        */ NULL,
    /* initialize_posthook       */ NULL,
    /* set_values_posthook       */ NULL,
    /* secondary_object_class    */ NULL,
    /* secondary_object_create   */ NULL,
    /* get_secondary_resources   */ NULL,
    /* fast_subclass             */ { 0 },
    /* get_values_prehook        */ NULL,
    /* get_values_posthook       */ NULL,
    /* class_part_init_prehook   */ NULL,
    /* class_part_init_posthook  */ NULL,
    /* ext_resources             */ NULL,
    /* compiled_ext_resources    */ NULL,
    /* num_ext_resources         */ 0,
    /* use_sub_resources         */ False,
    /* widget_navigable          */ widget_navigable,
    /* focus_change              */ NULL,
    /* wrapper_data              */ NULL
};

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

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

XmManagerClassRec xmManagerClassRec = {
    /* Core class part */
    {
	/* superclass            */ (WidgetClass) &constraintClassRec,
        /* class_name            */ "XmManager",
	/* widget_size           */ sizeof(XmManagerRec),
	/* 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   */ True,
	/* visible_interest      */ False,
	/* destroy               */ destroy,
	/* resize                */ NULL,
	/* expose                */ NULL,
	/* set_values            */ set_values,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ XtInheritSetValuesAlmost,
	/* get_values_hook       */ _XmManagerGetValuesHook,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ _XmManager_defaultTranslations,
	/* query_geometry        */ NULL,
	/* display_accelerator   */ NULL /*XtInheritDisplayAccelerator*/,
	/* extension             */ (XtPointer)&_XmManagerCoreClassExtRec
    },
    /* Composite class part */
    {
	/* geometry manager */ geometry_manager,
        /* change_managed   */ changed_managed,
        /* insert_child     */ XtInheritInsertChild,
        /* delete_child     */ XtInheritDeleteChild,
        /* extension        */ (XtPointer)&managerCompositeExt,
    },
    /* Constraint class part */
    {
	/* subresources      */ NULL,
        /* subresource_count */ 0,
        /* constraint_size   */ 0,
        /* initialize        */ constraint_initialize,
        /* destroy           */ NULL,
        /* set_values        */ NULL,
        /* extension         */ NULL,
    },
    /* XmManager class part */
    {
	/* translations                 */ _XmManager_managerTraversalTranslations,
        /* syn_resources                */ syn_resources,
        /* num_syn_resources            */ XtNumber(syn_resources),
        /* syn_constraint_resources     */ NULL,
        /* num_syn_constraint_resources */ 0,
        /* parent_process               */ _XmParentProcess,
	/* extension                    */ (XtPointer)&_XmManagerClassExtRec
    },
};
/* *INDENT-ON* */


WidgetClass xmManagerWidgetClass = (WidgetClass)&xmManagerClassRec;

static void
class_initialize()
{
    _XmRegisterConverters();
    _XmRegisterPixmapConverters();
    _XmInitializeExtensions();
    _XmManagerCoreClassExtRec.record_type = XmQmotif;
}

static void
class_part_initialize(WidgetClass widget_class)
{
    XmManagerWidgetClass mwc = (XmManagerWidgetClass)widget_class;
    XmManagerWidgetClass swc = (XmManagerWidgetClass)widget_class->core_class.superclass;
    CompositeClassExtension ext, *extptr;

    if (mwc->manager_class.translations == XtInheritTranslations)
    {
	mwc->manager_class.translations =
	    swc->manager_class.translations;
    }
    else if (mwc->manager_class.translations != NULL)
    {
	mwc->manager_class.translations =
	    (String)XtParseTranslationTable(mwc->manager_class.translations);
    }
    if (mwc->manager_class.parent_process == XmInheritParentProcess)
    {
	mwc->manager_class.parent_process =
	    swc->manager_class.parent_process;
    }
    extptr = (CompositeClassExtension *)_XmGetClassExtensionPtr(
			(XmGenericClassExt *)&(mwc->composite_class.extension),
								   NULLQUARK);

    if (extptr == NULL || *extptr == NULL)
    {
	ext = (CompositeClassExtension)XtNew(CompositeClassExtensionRec);
	if (ext != NULL)
	{
	    ext->next_extension = mwc->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
	    mwc->composite_class.extension = (XtPointer)ext;
	}
    }


    if (widget_class != xmManagerWidgetClass)
    {
	XmManagerClassExt *mce = NULL, *sce = NULL;

	mce = _XmGetManagerClassExtPtr(mwc, NULLQUARK);
	sce = _XmGetManagerClassExtPtr(swc, NULLQUARK);

	if (mce && !*mce && sce && *sce)
	{
	    *mce =
	      (XmManagerClassExtRec *)XtCalloc(1, sizeof(XmManagerClassExtRec));
	    (*mce)->next_extension = NULL;
	    (*mce)->record_type = NULLQUARK;
	    (*mce)->version = XmManagerClassExtVersion;
	    (*mce)->record_size = sizeof(XmManagerClassExtRec);
	    (*mce)->traversal_children = (*sce)->traversal_children;
	}
	else if (mce && sce && *mce && *sce)
	{
	    if ((*mce)->traversal_children == XmInheritTraversalChildrenProc)
	    {
		(*mce)->traversal_children =
		    (*sce)->traversal_children;
	    }
	}
    }

    _XmBaseClassPartInitialize(widget_class);
    _XmFastSubclassInit(widget_class, XmMANAGER_BIT);

    /* compile the resources */
    if (widget_class == xmManagerWidgetClass)
    {
	_XmSortResourceList((XrmResource **)mwc->core_class.resources,
			    mwc->core_class.num_resources);
    }

    _XmInitializeSyntheticResources(mwc->manager_class.syn_resources,
				    mwc->manager_class.num_syn_resources);
    _XmInitializeSyntheticResources(mwc->manager_class.syn_constraint_resources,
				    mwc->manager_class.num_syn_constraint_resources);

    if (widget_class != xmManagerWidgetClass)
    {
	XmManagerWidgetClass msc =
	(XmManagerWidgetClass)mwc->core_class.superclass;

	_XmBuildResources(&mwc->manager_class.syn_resources,
			  &mwc->manager_class.num_syn_resources,
			  msc->manager_class.syn_resources,
			  msc->manager_class.num_syn_resources);

	_XmBuildResources(&mwc->manager_class.syn_constraint_resources,
			  &mwc->manager_class.num_syn_constraint_resources,
			  msc->manager_class.syn_constraint_resources,
			  msc->manager_class.num_syn_constraint_resources);
    }
}

static void
CreateHighlightGC(Widget mw)
{
    XGCValues values;
    unsigned long mask;

    mask = GCForeground | GCBackground;
    values.foreground = MGR_HighlightColor(mw);
    values.background = XtBackground(mw);

    if (MGR_HighlightPixmap(mw) != None
	&& MGR_HighlightPixmap(mw) != XmUNSPECIFIED_PIXMAP)
    {
	/* we're dealing with a pixmap'ed highlight */
	mask |= GCTile | GCFillStyle;

	values.tile = MGR_HighlightPixmap(mw);
	values.fill_style = FillTiled;
    }

    mask |= GCLineWidth | GCLineStyle | GCJoinStyle | GCCapStyle;
    values.line_width = 1;
    values.line_style = LineSolid;
    values.join_style = JoinMiter;
    values.cap_style = CapButt;

    MGR_HighlightGC(mw) = XtGetGC((Widget)mw, mask, &values);
}

static void
CreateBottomShadowGC(Widget mw)
{
    XGCValues values;
    unsigned long mask;

    mask = GCForeground | GCBackground;
    values.foreground = MGR_BottomShadowColor(mw);
    values.background = XtBackground(mw);

    if (MGR_BottomShadowPixmap(mw) != None
	&& MGR_BottomShadowPixmap(mw) != XmUNSPECIFIED_PIXMAP)
    {
	/* we're dealing with a pixmap'ed bottom shadow */
	mask |= GCTile | GCFillStyle;

	values.tile = MGR_BottomShadowPixmap(mw);
	values.fill_style = FillTiled;
    }

    mask |= GCLineWidth;
    values.line_width = 1;

    MGR_BottomShadowGC(mw) = XtGetGC((Widget)mw, mask, &values);
}

static void
CreateTopShadowGC(Widget mw)
{
    XGCValues values;
    unsigned long mask;

    mask = GCForeground | GCBackground;
    values.foreground = MGR_TopShadowColor(mw);
    values.background = XtBackground(mw);

    if (MGR_TopShadowPixmap(mw) != None
	&& MGR_TopShadowPixmap(mw) != XmUNSPECIFIED_PIXMAP)
    {
	/* we're dealing with a pixmap'ed top shadow */
	mask |= GCTile | GCFillStyle;

	values.tile = MGR_TopShadowPixmap(mw);
	values.fill_style = FillTiled;
    }

    /* these GC's get used for shadow drawing, so set 'em up */
    mask |= GCLineWidth | GCLineStyle | GCJoinStyle | GCCapStyle;
    values.line_width = 1;
    values.line_style = LineSolid;
    values.join_style = JoinMiter;
    values.cap_style = CapButt;

    MGR_TopShadowGC(mw) = XtGetGC((Widget)mw, mask, &values);
}

static void
CreateBackgroundGC(Widget mw)
{
    XGCValues values;
    unsigned long mask;

    mask = GCForeground | GCBackground;

    values.foreground = XtBackground(mw);
    values.background = XtBackground(mw);

    /* these GC's get used for shadow drawing, so set 'em up */
    mask |= GCLineWidth | GCLineStyle | GCJoinStyle | GCCapStyle;
    values.line_width = 1;
    values.line_style = LineSolid;
    values.join_style = JoinMiter;
    values.cap_style = CapButt;

    MGR_BackgroundGC(mw) = XtGetGC((Widget)mw, mask, &values);
}

static void
initialize(Widget request,
	   Widget new_w,
	   ArgList args,
	   Cardinal *num_args)
{
    XmManagerWidgetClass mwc = (XmManagerWidgetClass)new_w->core.widget_class;

    MGR_EventHandlerAdded(new_w) = False;
    MGR_HighlightedWidget(new_w) = NULL;
    MGR_SelectedGadget(new_w) = NULL;
    MGR_ActiveChild(new_w) = NULL;
    MGR_KeyboardList(new_w) = NULL;
    MGR_NumKeyboardEntries(new_w) = 0;
    MGR_SizeKeyboardList(new_w) = 0;

    if (!XmRepTypeValidValue(XmRepTypeGetId(XmRUnitType),
			     MGR_UnitType(new_w),
			     new_w))
    {
	MGR_UnitType(new_w) = XmPIXELS;
    }


    /* initialize these to values that aren't possible */
    if (!XmRepTypeValidValue(XmRepTypeGetId(XmRNavigationType),
			     MGR_NavigationType(new_w),
			     new_w))
    {
	MGR_UnitType(new_w) = XmTAB_GROUP;
    }

    /* This is way too simple. FIX ME */
    if (MGR_StringDirection(new_w) == (XmStringDirection)XmUNSPECIFIED)
    {
	if (XmIsManager(XtParent(new_w)))
	{
	    MGR_StringDirection(new_w) = MGR_StringDirection(XtParent(new_w));
	}
	else
	{
	    MGR_StringDirection(new_w) = XmSTRING_DIRECTION_L_TO_R;
	}
    }

    _XmNavigInitialize(request, new_w, args, num_args);

    _XmManagerImportArgs(new_w, args, num_args);

    if (mwc->manager_class.translations)
    {
	XtOverrideTranslations(new_w,
			       (XtTranslations)mwc->
					manager_class.translations);
    }

    /*
     * there's a really nasty reason for this.  CoreBackgroundPixmap() is
     * field that appears in *all* Core derivatives -- including Shell.
     * If we try to convert a string to a pixmap in for Shells, we'll have
     * a real nasty mess with infinite recursion.  This is because
     * we want to use XmGetPixmapByDepth(), but that function uses 
     * XmGetXmScreen() -- which is a VendorShell derivative.  Now consider
     * the case where we say "*.backgroundPixmap: slant_left", and we create
     * our first AppShell.  Neither the XmScreen nor the XmDisplay has been
     * created yet.  The converter proc will call XmGetPixmapByDepth(), which
     * will call XmGetXmScreen(), which will try to create the XmScreen, 
     * which is a VendorShell so the converter proc will be called, which
     * will call XmGetPixmapByDepth(), which ..... recursion.
     */
    if (_XmGetBGPixmapName() != NULL)
    {
        CoreBackgroundPixmap(new_w) =
                XmGetPixmapByDepth(XtScreen(new_w),
                                            _XmGetBGPixmapName(),
                                            MGR_Foreground(new_w),
                                            XtBackground(new_w),
                                            CoreDepth(new_w));
        _XmClearBGPixmap();
    }

    CreateTopShadowGC(new_w);
    CreateBottomShadowGC(new_w);
    CreateHighlightGC(new_w);
    CreateBackgroundGC(new_w);

    /* Install a Virtual Keys magic event handler on all widgets */
    XtAddEventHandler(new_w, KeyPressMask, False, _XmVirtKeysHandler, NULL);
}

static void
destroy(Widget w)
{
    XtReleaseGC(w, MGR_TopShadowGC(w));
    XtReleaseGC(w, MGR_BottomShadowGC(w));
    XtReleaseGC(w, MGR_HighlightGC(w));
    XtReleaseGC(w, MGR_BackgroundGC(w));

    if (MGR_EventHandlerAdded(w))
    {
	XtRemoveEventHandler(w,
			     PointerMotionMask,
			     False,
			     _XmManagerEventHandler,
			     NULL);
    }
    _XmNavigDestroy(w);
}

static void
realize(Widget w, XtValueMask *value_mask, XSetWindowAttributes *attributes)
{
    Boolean wz = False, hz = False;
    /*
     * MLM 960524 - if you get an XError: widget has zero width or height.
     */
    if (XtWidth(w) == 0)
    {
	wz = True;
	XtWidth(w) = 1;
    }
    if (XtHeight(w) == 0)
    {
	hz = True;
	XtHeight(w) = 1;
    }

    *value_mask |= CWDontPropagate|CWBitGravity;
    attributes->do_not_propagate_mask =
	(KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|
	 PointerMotionMask);
    attributes->bit_gravity = NorthWestGravity;

    XtCreateWindow(w, (unsigned int)InputOutput,
		   (Visual *)CopyFromParent, *value_mask, attributes);

    if (wz)
    {
	XtWidth(w) = 0;
    }
    if (hz)
    {
	XtHeight(w) = 0;
    }
}

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

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

    if (_XmGetBGPixmapName() != NULL)
    {
	XSetWindowAttributes attr;

        CoreBackgroundPixmap(new_w) =
                XmGetPixmapByDepth(XtScreen(new_w),
                                            _XmGetBGPixmapName(),
                                            MGR_Foreground(new_w),
                                            XtBackground(new_w),
                                            CoreDepth(new_w));

	attr.background_pixmap = CoreBackgroundPixmap(new_w);
	XChangeWindowAttributes(XtDisplay(new_w), XtWindow(new_w),
			        CWBackPixmap, &attr);

        _XmClearBGPixmap();
    }

    if (!XmRepTypeValidValue(XmRepTypeGetId(XmRUnitType),
			     MGR_UnitType(new_w),
			     new_w))
    {
	MGR_UnitType(new_w) = MGR_UnitType(old);
    }

    if (!XmRepTypeValidValue(XmRepTypeGetId(XmRNavigationType),
			     MGR_NavigationType(new_w),
			     new_w))
    {
	MGR_NavigationType(new_w) = MGR_NavigationType(old);
    }

    need_refresh = _XmNavigSetValues(old, request, new_w, args, num_args);

    if (MGR_ShadowThickness(old) != MGR_ShadowThickness(new_w)
	|| MGR_Foreground(old) != MGR_Foreground(new_w))
    {
	need_refresh = True;
    }

    if (MGR_HighlightColor(old) != MGR_HighlightColor(new_w)
	|| MGR_HighlightPixmap(old) != MGR_HighlightPixmap(new_w))
    {
	XtReleaseGC(new_w, MGR_HighlightGC(new_w));
	CreateHighlightGC(new_w);
	need_refresh = True;
    }

    if (MGR_BottomShadowColor(old) != MGR_BottomShadowColor(new_w)
	|| MGR_BottomShadowPixmap(old) != MGR_BottomShadowPixmap(new_w))
    {
	XtReleaseGC(new_w, MGR_BottomShadowGC(new_w));
	CreateBottomShadowGC(new_w);

	need_refresh = True;
    }

    if (MGR_TopShadowColor(old) != MGR_TopShadowColor(new_w)
	|| MGR_TopShadowPixmap(old) != MGR_TopShadowPixmap(new_w))
    {
	XtReleaseGC(new_w, MGR_TopShadowGC(new_w));
	CreateTopShadowGC(new_w);

	need_refresh = True;
    }

    if (XtBackground(old) != XtBackground(new_w))
    {
	XtReleaseGC(new_w, MGR_BackgroundGC(new_w));
	CreateBackgroundGC(new_w);

	need_refresh = True;
    }

    _XmManagerImportArgs(new_w, args, num_args);

    return need_refresh;
}

static XtGeometryResult
geometry_manager(Widget w,
		 XtWidgetGeometry *request,
		 XtWidgetGeometry *reply)
{
    /* Motif does not have this method */
    DEBUGOUT(XdbDebug(__FILE__, w, "geometry_manager()\n"));

    if (reply)
    {
	*reply = *request;
    }

    if (reply->request_mode & CWX)
    {
	XtX(w) = reply->x;
    }
    if (reply->request_mode & CWY)
    {
	XtY(w) = reply->y;
    }
    if (reply->request_mode & CWWidth)
    {
	XtWidth(w) = reply->width;
    }
    if (reply->request_mode & CWHeight)
    {
	XtHeight(w) = reply->height;
    }
    if (reply->request_mode & CWBorderWidth)
    {
	XtBorderWidth(w) = reply->border_width;
    }

    return XtGeometryYes;
}

static void
changed_managed(Widget w)
{
    /* Motif does not have this method */
    /* FIX ME */
    DEBUGOUT(XdbDebug(__FILE__, w, "ChangeManaged()\n"));


    _XmNavigChangeManaged(w);
}

/* constraint class methods */

static void
constraint_initialize(Widget request,
		      Widget new_w,
		      ArgList args,
		      Cardinal *num_args)
{
    Widget manager = XtParent(new_w);
    /* check to see if the gadget's event mask specifies an event
       that requires us to install an event handler. */

    if (XmIsGadget(new_w))
	if (!MGR_EventHandlerAdded(manager))
	{
	    /* we only need to check if we haven't already added one. */

	    if (G_EventMask(new_w) & XmMOTION_EVENT
		|| G_EventMask(new_w) & XmENTER_EVENT
		|| G_EventMask(new_w) & XmLEAVE_EVENT
		|| G_EventMask(new_w) & XmFOCUS_IN
		|| G_EventMask(new_w) & XmFOCUS_OUT)
	    {
		DEBUGOUT(XdbDebug(__FILE__, manager, "adding event handler\n"));

		XtAddEventHandler(manager,
				  PointerMotionMask | EnterWindowMask |
				  LeaveWindowMask,
				  True,
				  (XtEventHandler)_XmManagerEventHandler, NULL);

		MGR_EventHandlerAdded(manager) = True;
	    }
	}

}

void
_XmGadgetArm(Widget w,
	     XEvent *event,
	     String *params,
	     Cardinal *num_params)
{
    XButtonEvent *ev = (XButtonEvent *)event;
    Widget g = (Widget)_XmInputForGadget(w, ev->x, ev->y);

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmGadgetArm()\n"));

    if (_XmIsNavigable(g))
    {
	if (g)
	{
	    _XmDispatchGadgetInput(g,
				   event,
				   XmARM_EVENT);
	}

	MGR_SelectedGadget(w) = (XmGadget)g;
    }
}

void
_XmGadgetActivate(Widget w,
		  XEvent *event,
		  String *params,
		  Cardinal *num_params)
{
    Widget g = (Widget)MGR_SelectedGadget(w);

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmGadgetActivate()\n"));

    if (g)
    {
	_XmDispatchGadgetInput((Widget)g,
			       event,
			       XmACTIVATE_EVENT);
    }
    MGR_SelectedGadget(w) = NULL;
}

void
_XmGadgetMultiArm(Widget w,
		  XEvent *event,
		  String *params,
		  Cardinal *num_params)
{
    XButtonEvent *ev = (XButtonEvent *)event;
    Widget g = (Widget)_XmInputForGadget(w, ev->x, ev->y);

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmGadgetMultiArm()\n"));

    if (g)
    {
	_XmDispatchGadgetInput(g,
			       event,
			       XmMULTI_ARM_EVENT);

	MGR_SelectedGadget(w) = (XmGadget)g;
    }
}

void
_XmGadgetMultiActivate(Widget w,
		       XEvent *event,
		       String *params,
		       Cardinal *num_params)
{
    Widget g = (Widget)MGR_SelectedGadget(w);

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmGadgetMultiActivate()\n"));

    if (g)
    {
	_XmDispatchGadgetInput((Widget)g,
			       event,
			       XmMULTI_ACTIVATE_EVENT);
    }

    MGR_SelectedGadget(w) = NULL;
}

void
_XmGadgetDrag(Widget w,
	      XEvent *event,
	      String *params,
	      Cardinal *num_params)
{
    XButtonEvent *ev = (XButtonEvent *)event;
    Widget g = (Widget)_XmInputForGadget(w, ev->x, ev->y);

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmGadgetDrag()\n"));

    if (g)
    {
	_XmDispatchGadgetInput((Widget)g,
			       event,
			       XmBDRAG_EVENT);
    }
}

void
_XmGadgetSelect(Widget w,
		XEvent *event,
		String *params,
		Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    DEBUGOUT(XdbDebug2(__FILE__, w, g, "Inside _XmGadgetSelect()\n"));

    if (g && XmIsGadget(g))
    {
	XmGadgetClass gc = (XmGadgetClass)XtClass(g);

	if (gc->gadget_class.arm_and_activate)
	{
	    (*gc->gadget_class.arm_and_activate) (g, event, params, num_params);
	}
    }
}

void
_XmManagerParentActivate(Widget w,
			 XEvent *event,
			 String *params,
			 Cardinal *num_params)
{
    XmParentProcessDataRec data;
    XmManagerWidgetClass mwc = (XmManagerWidgetClass)w->core.widget_class;

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside ManagerParentActivate()\n"));

    data.input_action.process_type = XmINPUT_ACTION;
    data.input_action.event = event;
    data.input_action.action = XmPARENT_ACTIVATE;
    data.input_action.params = params;
    data.input_action.num_params = num_params;

    if (XmIsManager(w) && mwc->manager_class.parent_process)
    {
	if (!(*mwc->manager_class.parent_process) (w, &data))
	{
	    /* propagate to parent? */
	}
    }
}

void
_XmGadgetTraversePrevTabGroup(Widget w,
			      XEvent *event,
			      String *params,
			      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_PREV_TAB_GROUP);
}

void
_XmGadgetTraverseNextTabGroup(Widget w,
			      XEvent *event,
			      String *params,
			      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_NEXT_TAB_GROUP);
}

void
_XmGadgetTraverseUp(Widget w,
		    XEvent *event,
		    String *params,
		    Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_UP);
}

void
_XmGadgetTraverseDown(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_DOWN);
}

void
_XmGadgetTraverseLeft(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_LEFT);
}

void
_XmGadgetTraverseRight(Widget w,
		       XEvent *event,
		       String *params,
		       Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    DEBUGOUT(XdbDebug(__FILE__, g,
		      "Manager XmProcessTraversal(TRAVERSE_RIGHT)\n"));

    XmProcessTraversal(g, XmTRAVERSE_RIGHT);
}

void
_XmGadgetTraverseHome(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_HOME);
}

void
_XmGadgetHelp(Widget w,
	      XEvent *event,
	      String *params,
	      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);
    Widget cur;
    XmAnyCallbackStruct cbs;

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmGadgetHelp()\n"));

    if (g)
    {
	_XmDispatchGadgetInput(g,
			       event,
			       XmHELP_EVENT);
    }
    else
    {
	cur = w;

	cbs.reason = XmCR_HELP;
	cbs.event = event;

	while (cur != NULL)
	{
	    if (XtHasCallbacks(w, XmNhelpCallback) == XtCallbackHasSome)
	    {
		XtCallCallbacks(w, XmNhelpCallback, (XtPointer)&cbs);
		return;
	    }

	    cur = XtParent(cur);
	}
    }
}

void
_XmGadgetKeyInput(Widget w,
		  XEvent *event,
		  String *params,
		  Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    DEBUGOUT(XdbDebug2(__FILE__, w, g, "Inside _XmGadgetKeyInput()\n"));
    DEBUGOUT(XdbDebug2(__FILE__, w, g,
		       "event type: %d code %08x\n",
		       event->type, event->xkey.keycode));

    if (g)
    {
	_XmDispatchGadgetInput(g,
			       event,
			       XmKEY_EVENT);
    }
}

void
_XmGadgetButtonMotion(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "Inside _XmGadgetButtonMotion(), gadget %s\n",
		      g ? XtName(g) : "(null)"));

    if (g)
    {
	_XmDispatchGadgetInput(g,
			       event,
			       XmMOTION_EVENT);
    }
}

void
_XmManagerParentCancel(Widget w,
		       XEvent *event,
		       String *params,
		       Cardinal *num_params)
{
    XmParentProcessDataRec data;
    XmManagerWidgetClass mwc = (XmManagerWidgetClass)w->core.widget_class;

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

    data.input_action.process_type = XmINPUT_ACTION;
    data.input_action.event = event;
    data.input_action.action = XmPARENT_CANCEL;
    data.input_action.params = params;
    data.input_action.num_params = num_params;

    if (XmIsManager(w) && mwc->manager_class.parent_process)
    {
	(*mwc->manager_class.parent_process) (w, &data);
    }
}

void
_XmGadgetTraversePrev(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_PREV);
}


void
_XmGadgetTraverseNext(Widget w,
		      XEvent *event,
		      String *params,
		      Cardinal *num_params)
{
    Widget g = MGR_ActiveChild(w);

    XmProcessTraversal(g, XmTRAVERSE_NEXT);
}

/*
 * yeah, right.  Who came up with these names, anyway?
 */
void
_XmSocorro(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
    XmAnyCallbackStruct cbs;

    DEBUGOUT(XdbDebug(__FILE__, w, "Inside _XmSocorro()\n"));

    cbs.reason = XmCR_HELP;
    cbs.event = event;

    while (w != NULL)
    {
	if (XtHasCallbacks(w, XmNhelpCallback) == XtCallbackHasSome)
	{
	    XtCallCallbacks(w, XmNhelpCallback, (XtPointer)&cbs);
	    return;
	}
	w = XtParent(w);
    }
}

/* we don't handle anything by default.  We leave that up to the other
 * manager widgets, like bulletin board. Just pop up to our parent*/
Boolean
_XmParentProcess(Widget widget,
		 XmParentProcessData data)
{
    Widget p = XtParent(widget);
    XmManagerWidgetClass mwc = (XmManagerWidgetClass)p->core.widget_class;

    if (XmIsManager(p) && mwc->manager_class.parent_process)
    {
	return ((*mwc->manager_class.parent_process) (p, data));
    }

    return False;
}

static void
_XmManagerEventHandler(Widget w,
		       XtPointer data,
		       XEvent *event,
		       Boolean *cont)
{
    XmGadget g;

    unsigned char foc;

    if (CoreBeingDestroyed(w))
    {
	return;
    }

    g = _XmInputForGadget(w, event->xmotion.x, event->xmotion.y);
    if (g == NULL)
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "### _XmManagerEventHandler(gadget NULL)\n"));
    }
    else
    {
	DEBUGOUT(XdbDebug2(__FILE__, w,
			   (Widget)g, "### _XmManagerEventHandler()\n"));
    }

    /* We've got to tie this into the focus policy.  If the focus mode is
     * explicit, we get focus in/out events.  If the focus mode is pointer,
     * we get enter/leave events.  Regardless, we get one or the other,
     * but not both.  You can see this in Motif/mwm, but not in LessTif/lmwm.
     * There's a lot of wacky stuff that Motif does in the BaseClass
     * extension procs.  This (at least for Gadgets) is one of them (the
     * FocusChange proc).
     * Started this, but currently it is a hack.  Focus in/out and Enter/Leave
     * look the same -- and they shouldn't.  The trouble I'm having is how
     * to distinguish the two cases.  It really needs to follow when the
     * Gadget gets the keyboard focus (er, well, really when the parent
     * gets the keyboard focus). MLM
     *
     * 960720 -- fixed this.  Now this event handler only does the work for
     * XmPOINTER.  XmEXPLICIT is handled via the focus mechanism in Traversal.c
     * MLM
     *
     * 961114 -- Sometimes I am slow.  POINTER or InDragMode, stupid.  MLM
     */
    foc = _XmGetFocusPolicy(w);

    if (g == NULL)
    {
	/* 
	 * we're now not in a gadget child, or the child isn't listening
	 * 
	 * if we weren't in a gadget before, do nothing.
	 * else
	 * if we were in a gadget before, send a leave event to the old gadget
	 */

	if (MGR_HighlightedWidget(w) != NULL)
	{
	    DEBUGOUT(XdbDebug(__FILE__, w, "Sending LEAVE event to gadget\n"));
	    _XmDispatchGadgetInput(MGR_HighlightedWidget(w),
				   event,
				   XmLEAVE_EVENT);

	    if (foc == XmPOINTER || (XmIsRowColumn(w) && _XmGetInDragMode(w)))
		MGR_HighlightedWidget(w) = NULL;
	}
    }
    else
    {
	/* we are in a gadget child 
	 * if we weren't in a gadget before, send an enter event to the new
	 *    gadget
	 * else
	 * if we were in a gadget before:
	 *    if it's the same gadget, send a motion event.
	 *    else
	 *    it it's not the same gadget, send a leave event to the old
	 *       one and an enter event to the new one.
	 */

	if (MGR_HighlightedWidget(w) == NULL)
	{
	    DEBUGOUT(XdbDebug(__FILE__, w, "Sending ENTER event to gadget\n"));

	    _XmDispatchGadgetInput((Widget)g,
				   event,
				   XmENTER_EVENT);
	    if (foc == XmPOINTER || (XmIsRowColumn(w) && _XmGetInDragMode(w)))
		MGR_HighlightedWidget(w) = (Widget)g;
	}
	else
	{
	    /* the motion events are already propagated to highlightedwidget */
	    if (MGR_HighlightedWidget(w) != (Widget)g)
	    {

		DEBUGOUT(XdbDebug(__FILE__, w,
				  "Sending LEAVE event to old gadget\n"));

		_XmDispatchGadgetInput(MGR_HighlightedWidget(w),
				       event,
				       XmLEAVE_EVENT);

		DEBUGOUT(XdbDebug(__FILE__, w,
				  "Sending ENTER event to new gadget\n"));

		_XmDispatchGadgetInput((Widget)g,
				       event,
				       XmENTER_EVENT);

		if (foc == XmPOINTER ||
		    (XmIsRowColumn(w) && _XmGetInDragMode(w)))
		{
		    MGR_HighlightedWidget(w) = (Widget)g;
		}
	    }
	}
    }
}

void
_XmDestroyParentCallback(Widget w, XtPointer client, XtPointer call)
{
}

void
_XmClearShadowType(Widget w,
		   Dimension old_width, Dimension old_height,
		   Dimension old_shadow_thickness,
		   Dimension old_highlight_thickness)
{
}

/*
 * Accelerators and Mnemonics -  How they work.
 *
 * Accelerators are an issue to be dealt with on a per "window" basis -
 * if you take the user's perception of a window.
 * We collect the information on accelerators in the Menu Bar (a RowColumn
 * hence a subclass of Manager).
 *
 * Information on mnemonics is stored in the menu pane itself - also a
 * RowColumn.
 *
 * MENU BAR Mnemonics:
 * Two cases :
 * If one of the cascades in the menu bar has been activated, then
 *      the mnemonic's key by itself should trigger the corresponding
 *      cascade button.
 * If the menu bar is not selected, then Alt+the mnemonic should work.
 *
 * Only the latter case is treated here - the other is treated by ???
 * when the menu is activated, either through the mouse or the keyboard.
 *
 * MENU PULLDOWN Mnemonics:
 * If the menu is up and has the focus, then the mnemonic's key
 * by itself should trigger the widget
 *
 * MENU OPTION Mnemonics:
 * FIX ME -- don't know what this is supposed to do
 */
static void
_XmAcceleratorHandler(Widget w, XtPointer client_data,
		      XEvent *event, Boolean *cont)
{
    int i;
    XtActionProc act = NULL;

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "Got Accelerator key: type %d code %04x "
		      "state %08x data %08x\n",
		      event->type, event->xkey.keycode, event->xkey.state,
		      client_data));

    if (!XmIsManager(w) ||
	(event->type != KeyPress && event->type != KeyRelease))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "Bad match for event.  Not manager or bad event.\n"));
	return;
    }

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "Got Accelerator key: code: %08x state: %08x cd %08x %s\n",
		      event->xkey.keycode, event->xkey.state, client_data,
		      XtName(client_data)));

    for (i = 0; i < MGR_NumKeyboardEntries(w); i++)
    {
	if (MGR_KeyboardList(w)[i].eventType == event->type &&
	    MGR_KeyboardList(w)[i].key == event->xkey.keycode &&
	    MGR_KeyboardList(w)[i].modifiers == event->xkey.state &&
	    MGR_KeyboardList(w)[i].component == client_data)
	{
	    Widget comp = (Widget)client_data;
	    Cardinal num_params = 0;

	    DEBUGOUT(XdbDebug(__FILE__, w,
			      "MATCH!!!! "
			      "code %08x state %08x name: %s:%s mnem: %d\n",
			      event->xkey.keycode, event->xkey.state,
			      comp
				? comp->core.widget_class->core_class.class_name
				: "(nil)",
			      comp ? XtName(comp) : "(nil)",
			      MGR_KeyboardList(w)[i].isMnemonic));

	    /* Make sure XmGetPostedFromWidget works: ? */

	    if (XmIsPrimitive(MGR_KeyboardList(w)[i].component))
	    {
		act = PrimC_ArmAndActivate(XtClass(comp));

		(*act)(comp, event, NULL, &num_params);
	    }
	    else if (XmIsGadget(MGR_KeyboardList(w)[i].component))
	    {
		act = GC_ArmAndActivate(XtClass(comp));

		(*act)(comp, event, NULL, &num_params);
	    }
	    else if (XmIsRowColumn(w))
	    {
		act = RCClass_ArmAndActivate(XtClass(comp));

		(*act)(comp, event, NULL, &num_params);
	    }
	    else
	    {
		DEBUGOUT(XdbDebug(__FILE__, MGR_KeyboardList(w)[i].component,
				  "Not a widget/gadget\n"));

		XtCallActionProc(comp, "Activate", event, NULL, 0);
	    }

	    *cont = False;

	    break;
	}
    }
}

static void
AddKeyboardEntry(Widget m, Widget w, XmKeyboardData *item)
{
    int i;

    /* Register with the manager widget */
    if (MGR_NumKeyboardEntries(m) == 0 ||
	(MGR_NumKeyboardEntries(m) == MGR_SizeKeyboardList(m)))
    {
	i = MGR_SizeKeyboardList(m);

	if (MGR_SizeKeyboardList(m) == 0)
	{
	    MGR_SizeKeyboardList(m) = 8;
	    MGR_KeyboardList(m) =
		(XmKeyboardData *)XtMalloc(sizeof(XmKeyboardData) *
					   MGR_SizeKeyboardList(m));
	}
	else
	{
	    MGR_SizeKeyboardList(m) *= 2;
	    MGR_KeyboardList(m) =
		(XmKeyboardData *)XtRealloc((XtPointer)MGR_KeyboardList(m),
					    sizeof(XmKeyboardData) *
					    MGR_SizeKeyboardList(m));
	}

	if (MGR_SizeKeyboardList(m) > i)
	{
	    bzero(&MGR_KeyboardList(m)[i],
		  (MGR_SizeKeyboardList(m) - i) * sizeof(XmKeyboardData));
	}
    }
    else
    {
	i = MGR_NumKeyboardEntries(m);
    }

    if (MGR_KeyboardList(m)[i].component != NULL)
    {
	_XmError(m, "This should not happen: %d\n", i);
    }

    bcopy(item, &MGR_KeyboardList(m)[i], sizeof(XmKeyboardData));

    MGR_NumKeyboardEntries(m)++;

    DEBUGOUT(XdbDebug(__FILE__, m,
		      "GrabKey: key %04x Sym: %04x modifiers %08x\n",
		      item->key, item->keysym, item->modifiers));

    XtInsertEventHandler(m, KeyPressMask|KeyReleaseMask,
			 False, _XmAcceleratorHandler,
			 (XtPointer)w, XtListHead);

    if (item->needGrab)
    {
	XtGrabKey(m, item->key, item->modifiers, False,
		  GrabModeAsync, GrabModeAsync);
    }
}

static void
DeleteKeyboardEntry(Widget m, Widget w, Boolean isMnemonic)
{
    int i;

    /* Danger, Will Robinson */
    if (CoreBeingDestroyed(m))
    {
	return;
    }

    for (i = 0; i < MGR_NumKeyboardEntries(m); i++)
    {
	if (MGR_KeyboardList(m) && w == MGR_KeyboardList(m)[i].component &&
	    ((MGR_KeyboardList(m)[i].isMnemonic && isMnemonic) ||
	     (!MGR_KeyboardList(m)[i].isMnemonic && !isMnemonic)))
	{
	    XmKeyboardData *data = &MGR_KeyboardList(m)[i];

	    XtRemoveEventHandler(m, data->eventType, False,
				 _XmAcceleratorHandler, w);

	    if (data->needGrab)
	    {
		XtUngrabKey(m, data->key, data->modifiers);
	    }

	    if (i < MGR_NumKeyboardEntries(m) - 1)
	    {
		bcopy(&MGR_KeyboardList(m)[i + 1],
		      &MGR_KeyboardList(m)[i],
		      sizeof(XmKeyboardData) *
			(MGR_NumKeyboardEntries(m) - i - 1));

		bzero(&MGR_KeyboardList(m)[MGR_NumKeyboardEntries(m) - 1],
		      sizeof(XmKeyboardData));
	    }
	    /* end of list */
	    else
	    {
		bzero(&MGR_KeyboardList(m)[i], sizeof(XmKeyboardData));
	    }

	    MGR_NumKeyboardEntries(m)--;
	    break;
	}
    }
}

void
_XmManagerInstallAccelerator(Widget m, Widget w, String s)
{
    Widget mw, sh;
    int eventType = 0;
    unsigned keysym = 0;
    unsigned int modifiers = 0;
    XmKeyboardData data;

    DEBUGOUT(XdbDebug2(__FILE__, m, w,
		       "_XmManagerInstallAccelerator(%s)\n", s));

    /* Do we really have an accelerator ? */
    if (s == NULL || strlen(s) == 0)
	return;

    /* Check whether we're in a menu system */
    mw = XtParent(w);
    if (!XmIsRowColumn(mw))
    {
	return;
    }

    if (!(RC_Type(mw) == XmMENU_PULLDOWN || RC_Type(mw) == XmMENU_OPTION))
    {
	return;
    }

    /* Find the manager widget just underneath the shell */
    for (mw = m; XtParent(mw); mw = sh)
    {
	sh = XtParent(mw);

	if (XtIsSubclass(sh, applicationShellWidgetClass) ||
	    XtIsSubclass(sh, xmDialogShellWidgetClass) ||
	    XtIsSubclass(sh, topLevelShellWidgetClass))
	{
	    break;
	}
    }

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "_XmManagerInstallAccelerator found manager %s\n",
		      XtName(mw)));


    _XmMapKeyEvent(s, &eventType, &keysym, &modifiers);

    /* Put the data in the entry */
    data.component = w;
    data.eventType = eventType;
    data.isMnemonic = False;
    data.keysym = keysym;
    data.key = XKeysymToKeycode(XtDisplay(w), data.keysym);
    data.modifiers = modifiers;
    data.needGrab = True;

    AddKeyboardEntry(mw, w, &data);
}

void
_XmManagerUninstallAccelerator(Widget m, Widget w)
{
    Widget mw, sh;

    /* Find the manager widget just underneath the shell */
    for (mw = m; XtParent(mw); mw = sh)
    {
	sh = XtParent(mw);
	if (XtIsSubclass(sh, applicationShellWidgetClass) ||
	    XtIsSubclass(sh, xmDialogShellWidgetClass) ||
	    XtIsSubclass(sh, topLevelShellWidgetClass))
	{
	    break;
	}
    }

    if (!XmIsManager(mw))
    {
	return;
    }

    DeleteKeyboardEntry(mw, w, False);
}

void
_XmManagerInstallMnemonic(Widget m, Widget w, KeySym mn)
{
    unsigned int modifiers = 0;
    Boolean need_grab = False;
    XmKeyboardData data;

    if (mn == 0 || mn == NoSymbol)
    {
	return;
    }

    DEBUGOUT(XdbDebug2(__FILE__, m, w, "_XmManagerInstallMnemonic(%c)\n", mn));

    /* If we're dealing with the menu bar, store the stuff in the highest
     * manager widget that you can find (with all the accelerators) */
    if (XmIsRowColumn(m) &&
	(RC_Type(m) == XmMENU_BAR || RC_Type(m) == XmMENU_OPTION))
    {
	Widget mw, sh;
	XmModifierMaskSetReference mods =
		_XmGetModifierMappingsForDisplay(XtDisplay(w));

	need_grab = True;
	modifiers |= mods[ALTModifier];

	for (mw = m; XtParent(mw); mw = sh)
	{
	    sh = XtParent(mw);
	    if (XtIsSubclass(sh, applicationShellWidgetClass) ||
		XtIsSubclass(sh, xmDialogShellWidgetClass) ||
		XtIsSubclass(sh, topLevelShellWidgetClass))
	    {
		break;
	    }
	}

	DEBUGOUT(XdbDebug2(__FILE__, mw, w, "Store mnemonic info\n"));
	m = mw;
    }

    if (XmIsManager(m))
    {
	/* Put the data in the entry */
	data.component = w;
	data.eventType = KeyPress;
	data.keysym = mn;
	data.isMnemonic = True;
	data.key = XKeysymToKeycode(XtDisplay(w), data.keysym);
	data.modifiers = modifiers;
	data.needGrab = need_grab;

	AddKeyboardEntry(m, w, &data);
    }
}

void
_XmManagerUninstallMnemonic(Widget m, Widget w)
{
    Widget mw, sh;

    if (XmIsRowColumn(m) && RC_Type(m) == XmMENU_BAR)
    {
	/* Find the manager widget just underneath the shell */
	for (mw = m; XtParent(mw); mw = sh)
	{
	    sh = XtParent(mw);
	    if (XtIsSubclass(sh, applicationShellWidgetClass) ||
		XtIsSubclass(sh, xmDialogShellWidgetClass) ||
		XtIsSubclass(sh, topLevelShellWidgetClass))
	    {
		break;
	    }
	}
    }
    else
    {
	mw = m;
    }

    if (!XmIsManager(mw))
    {
	return;
    }

    DeleteKeyboardEntry(mw, w, True);
}

static XmNavigability
widget_navigable(Widget w)
{
    if (XtSensitive(w) && MGR_TraversalOn(w))
    {
	if (MGR_NavigationType(w) == XmSTICKY_TAB_GROUP ||
	    MGR_NavigationType(w) == XmEXCLUSIVE_TAB_GROUP ||
	    (MGR_NavigationType(w) == XmTAB_GROUP && !_XmShellIsExclusive(w)))
	{
	    DEBUGOUT(XdbDebug(__FILE__, w,
			  "WidgetNavigable => XmDESCENDANTS_TAB_NAVIGABLE\n"));

	    return XmDESCENDANTS_TAB_NAVIGABLE;
	}
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "WidgetNavigable => XmDESCENDANTS_NAVIGABLE\n"));

	return XmDESCENDANTS_NAVIGABLE;
    }

    DEBUGOUT(XdbDebug(__FILE__, w, "WidgetNavigable => XmNOT_NAVIGABLE\n"));

    return XmNOT_NAVIGABLE;
}

void
_XmManagerHighlightPixmapDefault(Widget w, int offset, XrmValue *value)
{
	static Pixmap pixmap;  

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

	pixmap = XmUNSPECIFIED_PIXMAP;

	value->addr = (char *) &pixmap;
	value->size = sizeof (Pixmap);

	if (MGR_HighlightColor(w) == XtBackground(w))
		pixmap = XmGetPixmapByDepth(XtScreen(w), "50_foreground",
			MGR_HighlightColor(w),
			MGR_Foreground(w),
			CoreDepth(w));
}

void
_XmManagerTopShadowPixmapDefault(Widget w, int offset, XrmValue *value)
{
	static Pixmap pixmap;

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

	pixmap = XmUNSPECIFIED_PIXMAP;

	value->addr = (char *) &pixmap;
	value->size = sizeof (Pixmap);

	if (MGR_TopShadowColor(w) == XtBackground(w))
		pixmap = XmGetPixmapByDepth(XtScreen(w), "50_foreground",
			MGR_TopShadowColor(w),
			MGR_Foreground(w),
			CoreDepth(w));
	else if (DefaultDepthOfScreen(XtScreen(w)) == 1)
		pixmap = XmGetPixmapByDepth(XtScreen(w), "50_foreground",
			MGR_TopShadowColor(w),
			XtBackground(w),
			CoreDepth(w));
}
