/**
 *
 * $Id: MainW.c,v 1.21 1997/08/27 16:21:45 miers 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: MainW.c,v 1.21 1997/08/27 16:21:45 miers Exp $";

#include <LTconfig.h>
#include <XmI/XmI.h>
#include <stdio.h>
#include <Xm/XmP.h>
#include <Xm/ScrollBarP.h>
#include <Xm/BaseClassP.h>
#include <Xm/ScrolledWP.h>
#include <Xm/RowColumnP.h>
#include <Xm/CommandP.h>
#include <Xm/MainWP.h>
#include <Xm/SeparatoG.h>
#include <Xm/SeparatoGP.h>
#include <X11/Xfuncs.h>

#include <XmI/DebugUtil.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 destroy(Widget w);

static void resize(Widget w);

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

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 _XmMainWindowPreferredSize(Widget w, Widget child,
				       XtWidgetGeometry *cg, XmMWValues * vals);
static XtGeometryResult _XmMainWindowGeomRequest(Widget w, XmMWValues * vals);
static void _XmMainWindowLayout(Widget w, Widget child,
				XtWidgetGeometry *cg, XmMWValues * vals);
static void _XmMainWindowConfigureChildren(Widget w, Widget child,
					   XtWidgetGeometry *cg,
					   XmMWValues * vals);

void _XmConfigureScrollBars(Widget w, Widget child,
			    XtWidgetGeometry *childgeom, XmSWValues * vals);

void _XmRepositionScrolledWindow(Widget w,
				 XtPointer client,
				 XtPointer call);

void _XmFixupScrollBars(Widget w, Dimension ww, Dimension wh);

/*
 * Resources for the MainWindow class
 */
#define Offset(field) XtOffsetOf(XmMainWindowRec, mwindow.field)
static XtResource resources[] =
{
    {
	XmNcommandWindow, XmCCommandWindow, XmRWidget,
	sizeof(Widget), Offset(CommandWindow),
	XmRImmediate, NULL
    },
    {
  XmNcommandWindowLocation, XmCCommandWindowLocation, XmRCommandWindowLocation,
	sizeof(unsigned char), Offset(CommandLoc),
	XmRImmediate, (XtPointer)XmCOMMAND_ABOVE_WORKSPACE
    },
    {
	XmNmenuBar, XmCMenuBar, XmRWidget,
	sizeof(Widget), Offset(MenuBar),
	XmRImmediate, NULL
    },
    {
	XmNmessageWindow, XmCMessageWindow, XmRWidget,
	sizeof(Widget), Offset(Message),
	XmRImmediate, NULL
    },
    {
    XmNmainWindowMarginWidth, XmCMainWindowMarginWidth, XmRHorizontalDimension,
	sizeof(Dimension), Offset(margin_width),
	XmRImmediate, (XtPointer)0
    },
    {
    XmNmainWindowMarginHeight, XmCMainWindowMarginHeight, XmRVerticalDimension,
	sizeof(Dimension), Offset(margin_height),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNshowSeparator, XmCShowSeparator, XmRBoolean,
	sizeof(Boolean), Offset(ShowSep),
	XtRImmediate, (XtPointer)False
    }
};

static XmSyntheticResource syn_resources[] =
{
    {
	XmNmainWindowMarginWidth,
	sizeof(Dimension), Offset(margin_width),
	_XmFromHorizontalPixels, _XmToHorizontalPixels
    },
    {
	XmNmainWindowMarginHeight,
	sizeof(Dimension), Offset(margin_height),
	_XmFromVerticalPixels, _XmToVerticalPixels
    }
};

/* Add Actions and Translations -- FIX ME */
/* *INDENT-OFF* */
static XmBaseClassExtRec _XmMainWindowCoreClassExtRec = {
    /* 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          */ 0,/*********XmInheritWidgetNavigable,*/
    /* focus_change              */ 0,/*********XmInheritFocusChange,*/
    /* wrapper_data              */ NULL
};

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

XmMainWindowClassRec xmMainWindowClassRec = {
    /* Core class part */
    {
	/* superclass            */ (WidgetClass) &xmScrolledWindowClassRec,
        /* class_name            */ "XmMainWindow",
	/* widget_size           */ sizeof(XmMainWindowRec),
	/* class_initialize      */ class_initialize,
	/* class_part_initialize */ class_part_initialize,
	/* class_inited          */ False,
	/* initialize            */ initialize,
	/* initialize_hook       */ NULL,
	/* realize               */ realize,
	/* actions               */ NULL,
	/* num_actions           */ 0,
	/* resources             */ resources,
	/* num_resources         */ XtNumber(resources),
	/* xrm_class             */ NULLQUARK,
	/* compress_motion       */ True,
	/* compress_exposure     */ XtExposeCompressMultiple,
	/* compress_enterleave   */ True,
	/* visible_interest      */ False,
	/* destroy               */ destroy,
	/* resize                */ resize,
	/* expose                */ 0,/*******XtInheritExpose,*/
	/* set_values            */ set_values,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ 0,/******XtInheritSetValuesAlmost,*/
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ NULL,
	/* query_geometry        */ query_geometry,
	/* display_accelerator   */ NULL,
	/* extension             */ (XtPointer)&_XmMainWindowCoreClassExtRec
    },
    /* Composite class part */
    {
	/* geometry manager */ geometry_manager, 
        /* change_managed   */ change_managed, 
        /* insert_child     */ insert_child,
        /* delete_child     */ 0,/*********XtInheritDeleteChild,*/
        /* extension        */ NULL,
    },
    /* Constraint class part */
    {
	/* subresources      */ NULL,
        /* subresource_count */ 0,
        /* constraint_size   */ 0,
        /* initialize        */ NULL,
        /* destroy           */ NULL,
        /* set_values        */ NULL,
        /* extension         */ NULL,
    },
    /* XmManager class part */
    {
	/* translations                 */ 0,/******XmInheritTranslations,*/
	/* syn_resources                */ syn_resources,
	/* num_syn_resources            */ XtNumber(syn_resources),
	/* syn_constraint_resources     */ NULL,
	/* num_syn_constraint_resources */ 0,
	/* parent_process               */ 0,/******XmInheritParentProcess,*/
	/* extension                    */ (XtPointer)&_XmMainWMClassExtRec
    },
    /* XmScrolledWindow part */
    {
	/* extension */ NULL,
    },
    /* XmMainWindow part */
    {
	/* extension */ NULL,	
    },
};
/* *INDENT-ON* */


int AMIWIN_MainW(void)
{
_XmMainWindowCoreClassExtRec.widgetNavigable=XmInheritWidgetNavigable;
_XmMainWindowCoreClassExtRec.focusChange=XmInheritFocusChange;

xmMainWindowClassRec.translations=XmInheritTranslations;
xmMainWindowClassRec.parent_process=XmInheritParentProcess;
xmMainWindowClassRec.expose=XtInheritExpose;
xmMainWindowClassRec.set_values_almost=XtInheritSetValuesAlmost;
xmMainWindowClassRec.delete_child=XtInheritDeleteChild;
return(0);
}



WidgetClass xmMainWindowWidgetClass = (WidgetClass)&xmMainWindowClassRec;

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

static void
class_part_initialize(WidgetClass widget_class)
{
    _XmFastSubclassInit(widget_class, XmMAIN_WINDOW_BIT);
}

static void
initialize(Widget request, Widget new_w,
	   ArgList args, Cardinal *num_args)
{
    /* Revert setting from XmScrolledWindow's initialize */
    if (XtWidth(request) == 0)
    {
	XtWidth(new_w) = 0;
    }
    if (XtHeight(request) == 0)
    {
	XtHeight(new_w) = 0;
    }

    /* Override setting of XmScrolledWindow's Margin[Width|Height] resources */
    SW_MarginWidth(new_w) = MW_MarginWidth(new_w);
    SW_MarginHeight(new_w) = MW_MarginHeight(new_w);

    MW_Sep1(new_w) = (XmSeparatorGadget)XmCreateSeparatorGadget(new_w,
								"Separator1",
								args,
								*num_args);
    MW_Sep2(new_w) = (XmSeparatorGadget)XmCreateSeparatorGadget(new_w,
								"Separator2",
								args,
								*num_args);
    MW_Sep3(new_w) = (XmSeparatorGadget)XmCreateSeparatorGadget(new_w,
								"Separator3",
								args,
								*num_args);
    if (MW_ShowSep(new_w))
    {
	XtManageChild((Widget)MW_Sep1(new_w));
	XtManageChild((Widget)MW_Sep2(new_w));
	XtManageChild((Widget)MW_Sep3(new_w));
    }
}


static void
destroy(Widget w)
{
}

static Boolean
set_values(Widget old, Widget request, Widget new_w,
	   ArgList args, Cardinal *num_args)
{
    Boolean refresh = False;
#define NE(x)	(x(old) != x(new_w))

    if (NE(MW_CommandWindow) ||
	NE(MW_CommandLoc) ||
	NE(MW_MenuBar) ||
	NE(MW_MessageWindow))
    {
	refresh = True;
    }


    if (NE(MW_ShowSep))
    {
	if (MW_ShowSep(new_w))
	{
	    XtManageChild((Widget)MW_Sep1(new_w));
	    XtManageChild((Widget)MW_Sep2(new_w));
	    XtManageChild((Widget)MW_Sep3(new_w));
	}
	else
	{
	    XtUnmanageChild((Widget)MW_Sep1(new_w));
	    XtUnmanageChild((Widget)MW_Sep2(new_w));
	    XtUnmanageChild((Widget)MW_Sep3(new_w));
	}

	refresh = True;
    }

    if (NE(MW_MarginHeight))
    {
	SW_MarginHeight(new_w) = MW_MarginHeight(new_w);
	refresh = True;
    }

    if (NE(MW_MarginWidth))
    {
	SW_MarginWidth(new_w) = MW_MarginWidth(new_w);
	refresh = True;
    }

    if (refresh)
    {
	XmMWValues vals;

	_XmMainWindowPreferredSize(new_w, NULL, NULL, &vals);
	XtWidth(new_w) = vals.MwW;
	XtHeight(new_w) = vals.MwH;
    }

    return refresh;
}

static void
resize(Widget w)
{
    XmMWValues vals;

    DEBUGOUT(XdbDebug(__FILE__, w, "Resize (w %d h %d)\n",
		      XtWidth(w), XtHeight(w)));

    SW_FromResize(w) = True;

    _XmMainWindowPreferredSize(w, NULL, NULL, &vals);

    vals.MwW = XtWidth(w);
    vals.MwH = XtHeight(w);

    _XmMainWindowLayout(w, NULL, NULL, &vals);

    _XmMainWindowConfigureChildren(w, NULL, NULL, &vals);

    SW_FromResize(w) = False;
}

static void
realize(Widget w, Mask *value_mask, XSetWindowAttributes *attributes)
{
    XmMWValues vals;

    DEBUGOUT(XdbDebug(__FILE__, w, "Realize ...\n"));

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

    if (XtWidth(w) != 0 && XtWidth(w) != 1)
    {
	SW_GivenWidth(w) = XtWidth(w);
    }
    if (XtHeight(w) != 0 && XtHeight(w) != 1)
    {
	SW_GivenHeight(w) = XtHeight(w);
    }

    _XmMainWindowPreferredSize(w, NULL, NULL, &vals);

    _XmMainWindowGeomRequest(w, &vals);

    /* ordinarily, we'd look at the return code and reset w/h based on
     * it.  But our routine does that for us. */

    _XmMainWindowLayout(w, NULL, NULL, &vals);

    _XmMainWindowConfigureChildren(w, NULL, NULL, &vals);

    DEBUGOUT(XdbDebug(__FILE__, w, "Realize => size %d %d\n",
		      XtWidth(w), XtHeight(w)));
}

static XtGeometryResult
query_geometry(Widget w,
	       XtWidgetGeometry *intended,
	       XtWidgetGeometry *preferred)
{
    XtWidgetGeometry wants;
    XmMWValues vals;

    wants = *intended;

    _XmMainWindowPreferredSize(w, w, NULL, &vals);

    if (preferred)
    {
	preferred->width = vals.MwW;
	preferred->height = vals.MwH;
    }

    if (((wants.request_mode & CWWidth) &&
	 wants.width == preferred->width) &&
	((wants.request_mode & CWHeight) &&
	 wants.height == preferred->height))
    {
	return XtGeometryNo;
    }

    if ((wants.request_mode & CWWidth) &&
	wants.width != preferred->width)
    {
	return XtGeometryAlmost;	/* Something's different */
    }
    if ((wants.request_mode & CWHeight) &&
	wants.height != preferred->height)
    {
	return XtGeometryAlmost;	/* Something's different */
    }

    return XtGeometryYes;
}

static void
change_managed(Widget w)
{
    XmMWValues vals;

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

    if (SW_HSB(w) && XtIsManaged(SW_HSB(w)))
    {
	SW_HasHSB(w) = True;
    }
    else
    {
	SW_HasHSB(w) = False;
    }

    if (SW_VSB(w) && XtIsManaged(SW_VSB(w)))
    {
	SW_HasVSB(w) = True;
    }
    else
    {
	SW_HasVSB(w) = False;
    }

    _XmMainWindowPreferredSize(w, NULL, NULL, &vals);

    _XmMainWindowGeomRequest(w, &vals);

    /* ordinarily, we'd look at the return code and reset w/h based on
     * it.  But our routine does that for us. */

    _XmMainWindowLayout(w, NULL, NULL, &vals);

    _XmMainWindowConfigureChildren(w, NULL, NULL, &vals);
}

#define	VALID(w)	(w != NULL && XtIsManaged(w))

/*
 * This is the new implementation of MainWindow Layout.
 * Danny 16/1/1997
 *
 * Parameters :
 *      w is the MainWindow
 *      ParentResize - True if we are allowed to try to change our own size
 *      child - the 'instigator' (the child causing this request, its
 *              geometry should not be changed)
 *      TestMode - True if we're not allowed to change anything
 *      cg - the childs geometry
 *      mwg - return the mainwindow geometry
 *
 * Stuff to layout is :
 *      - MenuBar (MW_MenuBar)
 *      - Command Area (MW_CommandWindow)
 *      - Work Area (SW_WorkWindow)             note SW_
 *      - Message Area (MW_MessageWindow)
 * If MW_CommandLoc == XmCOMMAND_ABOVE_WORKSPACE then the order as given above.
 * Otherwise reverse order of Command Area and Work Area.
 *
 * If MW_ShowSep then separators (three) must be shown.
 */
static void
_XmMainWindowPreferredSize(Widget w, Widget child, XtWidgetGeometry *cg,
			   XmMWValues * vals)
{
    /* Dimension variables typed as int to allow for negative values. */
    Dimension curw, curh;

    bzero(vals, sizeof(XmMWValues));

    if (cg)
    {
	cg->request_mode &= (CWWidth | CWHeight | XtCWQueryOnly);
    }

    /*
     * As in all the complicated layout functions, this is the algorithm :
     * - keep everything in local variables for implementing TestMode
     * - first figure out how much space we need
     * - if we're allowed, request geometry change
     * - layout children (in local variables !) based on geometry
     *      which may be different from the geometry requested above
     * - if not in TestMode, apply all changes
     *      Otherwise, return some values in parameters.
     */

    /* Talk */
    DEBUGOUT(XdbDebug(__FILE__, w, "_XmMainWindowPreferredSize"));

    if (child)
    {
	DEBUGOUT(XdbDebug0(__FILE__, w, " Child %s, geo %s\n",
			   XtName(child), XdbWidgetGeometry2String(cg)));
    }

    /*
     * Find out how big we need to be.
     *      Only count SW_MarginWidth etc. at the end.
     *      Don't need to care about child order yet.
     */
    curw = curh = 0;

#define	Wants(xx)	(cg && ((cg->request_mode) & xx))

    vals->mbw = vals->mbh = vals->mbx = vals->mby = 0;
    if (VALID(MW_MenuBar(w)))
    {
	vals->mbw = XtWidth(MW_MenuBar(w));
	vals->mbh = XtHeight(MW_MenuBar(w));

	if (MW_MenuBar(w) == child)
	{
	    if (Wants(CWWidth))
	    {
		vals->mbw = cg->width;
	    }
	    if (Wants(CWHeight))
	    {
		vals->mbh = cg->height;
	    }
	}

	DEBUGOUT(XdbDebug2(__FILE__, w, MW_MenuBar(w),
			   "_XmMainWindoPreferredSize: menu bar w %d h %d\n",
			   vals->mbw, vals->mbh));

	curh += vals->mbh;
	if (curw < vals->mbw)
	{
	    curw = vals->mbw;
	}
    }

    vals->cww = vals->cwh = vals->cwx = vals->cwy = 0;
    if (VALID(MW_CommandWindow(w)))
    {
	vals->cww = XtWidth(MW_CommandWindow(w));
	vals->cwh = XtHeight(MW_CommandWindow(w));

	if (MW_CommandWindow(w) == child)
	{
	    if (Wants(CWWidth))
	    {
		vals->cww = cg->width;
	    }
	    if (Wants(CWHeight))
	    {
		vals->cwh = cg->height;
	    }
	}

	DEBUGOUT(XdbDebug2(__FILE__, w, MW_CommandWindow(w),
			   "_XmMainWindowPreferredSize:"
			   " command window w %d h %d\n",
			   vals->cww, vals->cwh));

	curh += vals->cwh;
	if (curw < vals->cww)
	{
	    curw = vals->cww;
	}
    }

    vals->mww = vals->mwh = vals->mwx = vals->mwy = 0;
    if (VALID(MW_MessageWindow(w)))
    {
	vals->mww = XtWidth(MW_MessageWindow(w));
	vals->mwh = XtHeight(MW_MessageWindow(w));

	if (MW_MessageWindow(w) == child)
	{
	    if (Wants(CWWidth))
	    {
		vals->mww = cg->width;
	    }
	    if (Wants(CWHeight))
	    {
		vals->mwh = cg->height;
	    }
	}

	DEBUGOUT(XdbDebug2(__FILE__, w, MW_MessageWindow(w),
			   "_XmMainWindowPreferredSize:"
			   " message window w %d h %d\n",
			   vals->mww, vals->mwh));

	curh += vals->mwh;
	if (curw < vals->mww)
	{
	    curw = vals->mww;
	}
    }

    vals->www = vals->wwh = vals->wwx = vals->wwy = 0;

    /* Print out how we're called */
    if (XdbInDebug(__FILE__, w))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "XmMainWPreferredSize [size %d %d]\n",
			  XtWidth(w), XtHeight(w)));
	DEBUGOUT(XdbDebug0(__FILE__, w, "... SW_VisualPolicy %s",
			   (SW_VisualPolicy(w) == XmCONSTANT) ? "XmCONSTANT" :
			   (SW_VisualPolicy(w) == XmVARIABLE) ? "XmVARIABLE" :
			   (SW_VisualPolicy(w) == XmRESIZE_IF_POSSIBLE)
			   ? "XmRESIZE_IF_POSSIBLE" : "???"));
	DEBUGOUT(XdbDebug0(__FILE__, w, " SW_ScrollBarPolicy %s",
			   (SW_ScrollBarPolicy(w) == XmSTATIC)
			   ? "XmSTATIC"
			   : (SW_ScrollBarPolicy(w) == XmAS_NEEDED)
			   ? "XmAS_NEEDED"
			   : "???"));
	DEBUGOUT(XdbDebug0(__FILE__, w, " SW_ScrollPolicy %s\n",
			   (SW_ScrollPolicy(w) == XmAPPLICATION_DEFINED)
			   ? "XmAPPLICATION_DEFINED"
			   : (SW_ScrollPolicy(w) == XmAUTOMATIC)
			   ? "XmAUTOMATIC"
			   : "???"));
    }

    /*
     * if you know scrolledWindow this should look very familiar.
     */
    if (SW_VSB(w))
    {
	/*
	 * Don't be confused by HasHSB having similar name to SW_HasHSB().
	 * HasHSB is true if the widget exists.
	 * ShowHSB is used to manage/unmanage the scrollbar.
	 */
	vals->HasVSB = True;
	vals->ShowVSB = False;
	vals->VsbX = XtX(SW_VSB(w));
	vals->VsbY = XtY(SW_VSB(w));
	vals->VsbW = XtWidth(SW_VSB(w));
	vals->VsbH = XtHeight(SW_VSB(w));
    }

    if (SW_HSB(w))
    {
	vals->HasHSB = True;
	vals->ShowHSB = False;
	vals->HsbX = XtX(SW_HSB(w));
	vals->HsbY = XtY(SW_HSB(w));
	vals->HsbW = XtWidth(SW_HSB(w));
	vals->HsbH = XtHeight(SW_HSB(w));
    }

    vals->ClipX = vals->ClipY = vals->WorkX = vals->WorkY = 0;
    vals->ClipW = vals->ClipH = vals->WorkW = vals->WorkH = 0;

    if (SW_WorkWindow(w))
    {
	vals->WorkX = vals->wwx;
	vals->WorkY = vals->wwy;

	if (SW_VisualPolicy(w) == XmVARIABLE && XtIsRealized(SW_WorkWindow(w)))
	{
	    XtWidgetGeometry workgeo;

	    XtQueryGeometry(SW_WorkWindow(w), NULL, &workgeo);
	    vals->WorkW = workgeo.width;
	    vals->WorkH = workgeo.height;
	}
	else
	{
	    vals->WorkW = XtWidth(SW_WorkWindow(w));
	    vals->WorkH = XtHeight(SW_WorkWindow(w));
	}

	DEBUGOUT(XdbDebug2(__FILE__, w, (Widget)SW_WorkWindow(w),
			   "WorkWindow queried geo is W %d H %d X %d Y %d\n",
			   vals->WorkW, vals->WorkH, vals->WorkX, vals->WorkY));
    }
    else
    {
	vals->WorkX = vals->wwx;
	vals->WorkY = vals->wwy;
	vals->WorkW = 0;
	vals->WorkH = 0;
    }

    if (cg)
    {
	/* only happens for APPLICATION_DEFINED */
	if (child == (Widget)SW_WorkWindow(w))
	{
	    if (cg->request_mode & CWWidth)
	    {
		vals->WorkW = cg->width;
	    }
	    if (cg->request_mode & CWHeight)
	    {
		vals->WorkH = cg->height;
	    }
	}
	/* only happens for AUTOMATIC */
	if (child == (Widget)SW_ClipWindow(w))
	{
	    if (cg->request_mode & CWWidth)
	    {
		vals->ClipW = cg->width;
	    }
	    if (cg->request_mode & CWHeight)
	    {
		vals->ClipH = cg->height;
	    }
	}
	if (child == (Widget)SW_HSB(w))
	{
	    if (cg->request_mode & CWWidth)
	    {
		vals->HsbW = cg->width;
	    }
	    if (cg->request_mode & CWHeight)
	    {
		vals->HsbH = cg->height;
	    }
	}
	if (child == (Widget)SW_VSB(w))
	{
	    if (cg->request_mode & CWWidth)
	    {
		vals->VsbW = cg->width;
	    }
	    if (cg->request_mode & CWHeight)
	    {
		vals->VsbH = cg->height;
	    }
	}
    }

    if (SW_ScrollPolicy(w) == XmAPPLICATION_DEFINED)
    {
	if (SW_ScrollBarPolicy(w) != XmSTATIC)
	{			/* Sanity check */
	    _XmWarning(w,
		       "_XmMainWPreferredSize: XmAPPLICATION_DEFINED"
		       " but not XmSTATIC");

	    SW_ScrollBarPolicy(w) = XmSTATIC;
	}

	vals->ShowHSB = SW_HSB(w) ? XtIsManaged(SW_HSB(w)) : False;
	vals->ShowVSB = SW_VSB(w) ? XtIsManaged(SW_VSB(w)) : False;

	/* If we're being resized (grown), make sure child follows */
	if (vals->WorkW < vals->www)
	{
	    Dimension xx = vals->WorkW;

	    vals->WorkW = vals->www - 2 * SW_MarginWidth(w) -
		2 * MGR_ShadowThickness(w) -
		(vals->ShowVSB
		 ? (SW_Spacing(w) + vals->VsbW)
		 : 0);

	    DEBUGOUT(XdbDebug2(__FILE__, w, SW_WorkWindow(w),
			       "Grow WorkW %d -> %d\n",
			       xx, vals->WorkW));
	}

	if (vals->WorkH < vals->wwh)
	{
	    Dimension xx = vals->WorkH;

	    vals->WorkH = vals->wwh -
		(vals->ShowHSB
		 ? (SW_Spacing(w) + vals->HsbH)
		 : 0);

	    DEBUGOUT(XdbDebug2(__FILE__, w, SW_WorkWindow(w),
			       "Grow WorkH %d -> %d\n",
			       xx, vals->WorkH));
	}

	/* If child is bigger than we are, grow (if we can) */
	if (!SW_FromResize(w) && SW_VisualPolicy(w) == XmVARIABLE)
	{
	    if (vals->WorkW > vals->www)
	    {
		Dimension xx = vals->www;

		vals->www = vals->WorkW +
		    (vals->ShowVSB ? (SW_Spacing(w) + vals->VsbW) : 0);

		DEBUGOUT(XdbDebug2(__FILE__, w, SW_WorkWindow(w),
				   "Grow www %d -> %d\n",
				   xx, vals->www));
	    }
	    if (vals->WorkH > vals->wwh)
	    {
		Dimension xx = vals->wwh;

		vals->wwh = vals->WorkH +
		    (vals->ShowHSB ? (SW_Spacing(w) + vals->HsbH) : 0);

		DEBUGOUT(XdbDebug2(__FILE__, w, SW_WorkWindow(w),
				   "Grow wwh %d -> %d\n",
				   xx, vals->wwh));
	    }
	}
    }
    else
	/* SW_ScrollPolicy(w) == XmAUTOMATIC */
    {
	/* We're in charge ! */

	if (SW_ScrollBarPolicy(w) == XmSTATIC)
	{
	    /* Always show */
	    vals->ShowHSB = vals->ShowVSB = True;
	}
	else
	{
	    /* do we need to display scrollbars ? */
	    vals->ShowHSB = vals->WorkW > vals->www;
	    vals->ShowVSB = vals->WorkH > vals->wwh;
	}
    }

    /*
     * What follows is code independent of XmAUTOMATIC/XmAPPLICATION_DEFINED
     *
     * Try to resize ourselves if necessary (and if we're allowed to).
     */
    if (SW_VisualPolicy(w) != XmCONSTANT && !SW_FromResize(w) &&
	(vals->www == 0 || vals->wwh == 0))
    {
	if (SW_GivenWidth(w) == 0)
	{
	    vals->www = vals->WorkW;
	}
	else
	{
	    vals->www = SW_GivenWidth(w);
	}
	if (SW_GivenHeight(w) == 0)
	{
	    vals->wwh = vals->WorkH;
	}
	else
	{
	    vals->wwh = SW_GivenHeight(w);
	}
    }

    DEBUGOUT(XdbDebug2(__FILE__, w, SW_WorkWindow(w),
		       "_XmMainWindowPreferredSize: work window w %d h %d\n",
		       vals->www, vals->wwh));

    curh += vals->wwh;
    if (curw < vals->www)
    {
	curw = vals->www;
    }

    vals->s1w = vals->s1h = vals->s1x = vals->s1y = 0;
    vals->s2w = vals->s2h = vals->s2x = vals->s2y = 0;
    vals->s3w = vals->s3h = vals->s3x = vals->s3y = 0;
    if (MW_ShowSep(w))
    {
	if (VALID(MW_Sep1(w)))
	{
	    vals->s1w = XtWidth(MW_Sep1(w));
	    vals->s1h = XtHeight(MW_Sep1(w));

	    if ((Widget)MW_Sep1(w) == child)
	    {
		if (Wants(CWWidth))
		{
		    vals->s1w = cg->width;
		}
		if (Wants(CWHeight))
		{
		    vals->s1h = cg->height;
		}
	    }

	    curh += vals->s1h;
	}
	if (VALID(MW_Sep2(w)))
	{
	    vals->s2w = XtWidth(MW_Sep2(w));
	    vals->s2h = XtHeight(MW_Sep2(w));

	    if ((Widget)MW_Sep2(w) == child)
	    {
		if (Wants(CWWidth))
		{
		    vals->s2w = cg->width;
		}
		if (Wants(CWHeight))
		{
		    vals->s2h = cg->height;
		}
	    }

	    curh += vals->s2h;
	}
	if (VALID(MW_Sep3(w)))
	{
	    vals->s3w = XtWidth(MW_Sep3(w));
	    vals->s3h = XtHeight(MW_Sep3(w));

	    if ((Widget)MW_Sep3(w) == child)
	    {
		if (Wants(CWWidth))
		{
		    vals->s3w = cg->width;
		}
		if (Wants(CWHeight))
		{
		    vals->s3h = cg->height;
		}
	    }

	    curh += vals->s3h;
	}
    }

    /* Now count them in */
    if (curw != 0 && curh != 0)
    {
	curw += 2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));
	curh += 2 * (SW_MarginHeight(w) + MGR_ShadowThickness(w));
    }

    vals->MwW = curw;
    vals->MwH = curh;
}
#undef	Wants

static XtGeometryResult
_XmMainWindowGeomRequest(Widget w, XmMWValues * vals)
{
    XtGeometryResult res;
    XtWidgetGeometry geo;

    /*
     * MLM: This breaks xmgr.  Don't do this!
     * Well, ok, don't use 100x100
     */
    if (SW_GivenWidth(w) != 0)
    {
	vals->MwW = SW_GivenWidth(w);
    }

    if (SW_GivenHeight(w) != 0)
    {
	vals->MwH = SW_GivenHeight(w);
    }

    geo.width = vals->MwW;
    geo.height = vals->MwH;
    geo.request_mode = CWWidth | CWHeight;

    DEBUGOUT(XdbDebug(__FILE__, w,
		      "_XmMainWindowGeomRequests: request geo %s: "
		      "am %d %d given: %d %d\n",
		      XdbWidgetGeometry2String(&geo),
		      XtWidth(w), XtHeight(w),
		      SW_GivenWidth(w), SW_GivenHeight(w)));

    if ((res = _XmMakeGeometryRequest(w, &geo)) == XtGeometryYes)
    {
	vals->MwW = geo.width;
	vals->MwH = geo.height;
    }
    else
    {
	vals->MwW = XtWidth(w);
	vals->MwH = XtHeight(w);

	DEBUGOUT(XdbDebug(__FILE__, w,
			  "_XmMainWindowGeomRequests CONF got %s\n",
			  XdbWidgetGeometry2String(&geo)));
    }

    return res;
}

static void
_XmMainWindowLayout(Widget w, Widget child, XtWidgetGeometry *cg,
		    XmMWValues * vals)
{
    Position curx, cury;
    Dimension bw, bh;

    /*
     * Now actually lay out the children.
     * Assume that resizing the widget larger than requested grows
     * the work area, and similarly with resizes smaller than requested.
     */
    curx = SW_MarginWidth(w) + MGR_ShadowThickness(w);
    cury = SW_MarginHeight(w) + MGR_ShadowThickness(w);

    if (VALID(MW_MenuBar(w)))
    {
	vals->mbx = curx;
	vals->mby = cury;
	vals->mbw = vals->MwW -
	    2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));

	cury += vals->mbh;
    }

    if (MW_ShowSep(w) && VALID(MW_Sep1(w)))
    {
	vals->s1x = curx;
	vals->s1y = cury;
	vals->s1w = vals->MwW -
	    2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));

	cury += vals->s1h;
    }

    if (MW_CommandLoc(w) == XmCOMMAND_ABOVE_WORKSPACE)
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "_XmMainWindowLayout COMMAND_ABOVE_WORKSPACE\n"));
	if (VALID(MW_CommandWindow(w)))
	{
	    vals->cwx = curx;
	    vals->cwy = cury;
	    vals->cww = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));

	    cury += vals->cwh;
	}
	if (MW_ShowSep(w) && VALID(MW_Sep2(w)))
	{
	    vals->s2x = curx;
	    vals->s2y = cury;
	    vals->s2w = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));

	    cury += vals->s2h;
	}

	vals->wwy = cury;

	/*
	 * Now work from below (in opposite direction) to get to the size
	 * of WorkWindow.
	 */
	cury = vals->MwH - SW_MarginHeight(w) - MGR_ShadowThickness(w);
	if (VALID(MW_MessageWindow(w)))
	{
	    vals->mwx = curx;
	    vals->mwy = cury - vals->mwh;
	    vals->mww = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));

	    cury = vals->mwy;
	}
	if (MW_ShowSep(w) && VALID(MW_Sep3(w)))
	{
	    vals->s3x = curx;
	    vals->s3y = cury - vals->s3h;
	    vals->s3w = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));

	    cury = vals->s3y;
	}

	if (VALID(SW_WorkWindow(w)))
	{
	    vals->wwx = curx;
	    /* Statement to set WWY is moved up to where CURY is still useful */
	    vals->www = vals->MwW - 2 * (SW_MarginWidth(w) +
					 MGR_ShadowThickness(w));
	    vals->wwh = cury - vals->wwy;
	}
    }
    else
    {				/* XmCOMMAND_BELOW_WORKSPACE */
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "_XmMainWindowLayout COMMAND_BELOW_WORKSPACE\n"));
	/*
	 * Start working from the bottom immediately, eventually getting
	 * to the WorkWindow which will have to swallow all size changes.
	 */
	vals->wwy = cury;	/* For later on */
	cury = vals->MwH - SW_MarginHeight(w) - MGR_ShadowThickness(w);

	if (VALID(MW_MessageWindow(w)))
	{
	    cury -= vals->mwh;

	    vals->mwx = curx;
	    vals->mwy = cury;
	    vals->mww = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));
	}
	if (MW_ShowSep(w) && VALID(MW_Sep3(w)))
	{
	    cury -= vals->s3h;

	    vals->s3x = curx;
	    vals->s3y = cury;
	    vals->s3w = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));
	}
	if (VALID(MW_CommandWindow(w)))
	{
	    cury -= vals->cwh;

	    vals->cwx = curx;
	    vals->cwy = cury;
	    vals->cww = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));
	}
	if (MW_ShowSep(w) && VALID(MW_Sep2(w)))
	{
	    cury -= vals->s2h;

	    vals->s2x = curx;
	    vals->s2y = cury;
	    vals->s2w = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));
	}

	if (VALID(SW_WorkWindow(w)))
	{
	    vals->wwx = curx;
	    /* See above. wwy = cury; */
	    vals->www = vals->MwW -
		2 * (SW_MarginWidth(w) + MGR_ShadowThickness(w));
	    vals->wwh = cury - vals->wwy;
	}
    }

    /*
     * Motif has certain layout details that don't seem to be documented other
     * than by looking at the behavior of their implementation.
     * One aspect is the presence of borders depending on whether you have
     * horizontal/vertical scrollbars.
     * Another is the actual size of those borders. The two statements below
     * took me weeks to figure out, because it turned out that our scrollbars
     * weren't traversable (which means they didn't highlight), so it actually
     * looked like the scrollbars were in the right place. Sigh.
     */
    bw = vals->HasHSB ? Prim_HighlightThickness(SW_HSB(w)) : 2;
    bh = vals->HasVSB ? Prim_HighlightThickness(SW_VSB(w)) : 2;

    switch (SW_Placement(w))
    {
    case XmTOP_RIGHT:
	/* Independent of scrollbars actually being there */
	vals->HsbY = vals->wwy;
	vals->VsbX = vals->wwx + vals->www - vals->VsbW;
	vals->VsbY = vals->HsbY + vals->HsbH + SW_Spacing(w) - bh;
	vals->HsbX = vals->wwx;

	break;

    case XmBOTTOM_LEFT:
	/* Independent of scrollbars actually being there */
	vals->HsbY = vals->wwy + vals->wwh - vals->HsbH;
	vals->VsbX = vals->wwx;
	vals->VsbY = vals->wwy;
	vals->HsbX = vals->VsbX + vals->VsbW + SW_Spacing(w) - bw;

	break;

    case XmTOP_LEFT:
	/* Independent of scrollbars actually being there */
	vals->HsbY = vals->wwy;
	vals->VsbX = vals->wwx;
	vals->VsbY = vals->HsbY + vals->HsbH + bh;
	vals->HsbX = vals->VsbX + vals->VsbW + bw;

	break;

    case XmBOTTOM_RIGHT:
    default:
	/* Independent of scrollbars actually being there */
	vals->HsbX = vals->wwx;
	vals->HsbY = vals->wwy + vals->wwh - vals->HsbH;
	vals->VsbY = vals->wwy;
	vals->VsbX = vals->wwx + vals->www - vals->VsbW;

	break;
    }

    /*
     * this part is independent of the locations
     */
    /* A starting point */
    vals->ClipX = vals->HsbX + MGR_ShadowThickness(w) + bw;
    vals->ClipY = vals->VsbY + MGR_ShadowThickness(w) + bh;
    vals->WorkX = vals->HsbX + MGR_ShadowThickness(w) + bw;
    vals->WorkY = vals->VsbY + MGR_ShadowThickness(w) + bh;

    if (vals->ShowHSB && vals->HasHSB)
    {
	if (vals->ShowVSB && vals->HasVSB)
	{
	    vals->ClipW = vals->www - bw - 2 * MGR_ShadowThickness(w)
		- SW_Spacing(w) - vals->VsbW;
	    vals->ClipH = vals->wwh - bh - 2 * MGR_ShadowThickness(w)
		- SW_Spacing(w) - vals->HsbH;

	    vals->VsbH = vals->ClipH + 2 * bh + 2 * MGR_ShadowThickness(w);
	    vals->HsbW = vals->ClipW + 2 * bw + 2 * MGR_ShadowThickness(w);
	}
	else
	{
	    vals->ClipW = vals->www - 2 * bw - 2 * MGR_ShadowThickness(w);
	    vals->ClipH = vals->wwh - 2 * bh - 2 * MGR_ShadowThickness(w)
		- SW_Spacing(w) - vals->HsbH;

	    vals->VsbH = vals->ClipH + 2 * MGR_ShadowThickness(w) + 2 * bh;
	    vals->HsbW = vals->ClipW + 2 * MGR_ShadowThickness(w) + 2 * bw;
	}
    }
    else if (vals->ShowVSB && vals->HasVSB)
    {
	vals->ClipW = vals->www - 2 * bw - 2 * MGR_ShadowThickness(w)
	    - SW_Spacing(w) - vals->VsbW;
	vals->ClipH = vals->wwh - 2 * bh - 2 * MGR_ShadowThickness(w);

	vals->VsbH = vals->ClipH + 2 * MGR_ShadowThickness(w) + 2 * bh;
	vals->HsbW = vals->ClipW + 2 * MGR_ShadowThickness(w) + 2 * bw;
    }
    else
    {
	/* No scrollbars -> no borders anywhere */
	vals->ClipX = vals->wwx + MGR_ShadowThickness(w);
	vals->ClipY = vals->wwy + MGR_ShadowThickness(w);
	vals->ClipW = vals->wwx + vals->www - vals->ClipX -
		MGR_ShadowThickness(w);
	vals->ClipH = vals->wwy + vals->wwh - vals->ClipY -
		MGR_ShadowThickness(w);

	vals->VsbH = vals->ClipH + 2 * MGR_ShadowThickness(w);
	vals->HsbW = vals->ClipW + 2 * MGR_ShadowThickness(w);
    }

    if (vals->HasHSB && !vals->ShowHSB)
    {
	int m;

	XtVaGetValues((Widget)SW_HSB(w), XmNminimum, &m, NULL);
	XtVaSetValues((Widget)SW_HSB(w), XmNvalue, m, NULL);
    }

    if (vals->HasVSB && !vals->ShowVSB)
    {
	int m;

	XtVaGetValues((Widget)SW_VSB(w), XmNminimum, &m, NULL);
	XtVaSetValues((Widget)SW_VSB(w), XmNvalue, m, NULL);
    }

    DEBUGOUT(XdbDebug0(__FILE__, w, "##############################\n"));
    DEBUGOUT(XdbDebug2(__FILE__, w, MW_MenuBar(w), "Menu Bar: %s\n",
		       MW_MenuBar(w)
		       ? XtClass(MW_MenuBar(w))->core_class.class_name
		       : "(null)"));
    DEBUGOUT(XdbDebug2(__FILE__, w, MW_CommandWindow(w), "Command Window: %s\n",
		       MW_CommandWindow(w)
		       ? XtClass(MW_CommandWindow(w))->core_class.class_name
		       : "(null)"));
    DEBUGOUT(XdbDebug2(__FILE__, w, MW_MessageWindow(w), "Message: %s\n",
		       MW_MessageWindow(w)
		       ? XtClass(MW_MessageWindow(w))->core_class.class_name
		       : "(null)"));
    DEBUGOUT(XdbDebug2(__FILE__, w, SW_WorkWindow(w), "Work: %s\n",
		       SW_WorkWindow(w)
		       ? XtClass(SW_WorkWindow(w))->core_class.class_name
		       : "(null)"));
    DEBUGOUT(XdbDebug2(__FILE__, w, (Widget)SW_ClipWindow(w),
		       "Clip @ x %d y %d w %d h %d\n",
		       vals->ClipX, vals->ClipY, vals->ClipW, vals->ClipH));
    DEBUGOUT(XdbDebug0(__FILE__, w,
		       "HSB @ x %d y %d w %d h %d\n",
		       vals->HsbX, vals->HsbY, vals->HsbW, vals->HsbH));
    DEBUGOUT(XdbDebug0(__FILE__, w,
		       "VSB @ x %d y %d w %d h %d\n",
		       vals->VsbX, vals->VsbY, vals->VsbW, vals->VsbH));
    DEBUGOUT(XdbDebug0(__FILE__, w,
		       "HasHSB %s ShowHSB %s HasVSB %s ShowVSB %s\n",
		       vals->HasHSB ? "True" : "False",
		       vals->ShowHSB ? "True" : "False",
		       vals->HasVSB ? "True" : "False",
		       vals->ShowVSB ? "True" : "False"));
    DEBUGOUT(XdbDebug0(__FILE__, w,
	      "MarginWidth %d MarginHeight %d ShadowThickness %d Spacing %d\n",
		       SW_MarginWidth(w), SW_MarginHeight(w),
		       MGR_ShadowThickness(w), SW_Spacing(w)));
    DEBUGOUT(XdbDebug0(__FILE__, w,
		       "x %d y %d www %d wwh %d\n", vals->wwx, vals->wwy,
		       vals->www, vals->wwh));
    DEBUGOUT(XdbDebug0(__FILE__, w, "##############################\n"));

    if (SW_ScrollPolicy(w) == XmAPPLICATION_DEFINED)
    {
	vals->WorkW = vals->ClipW;
	vals->WorkH = vals->ClipH;
	vals->WorkX = vals->ClipX;
	vals->WorkY = vals->ClipY;
    }

    /*
     * In the code above (all of the switch statement really), some
     * variables can become negative where we don't want them to.
     * Fix that here by giving them their original value from the
     * widget resource they represent.
     */
    if (vals->ClipH < 0)
    {
	vals->ClipH = SW_ClipWindow(w) ? XtHeight(SW_ClipWindow(w)) : 0;
    }
    if (vals->ClipW < 0)
    {
	vals->ClipW = SW_ClipWindow(w) ? XtWidth(SW_ClipWindow(w)) : 0;
    }
    if (vals->WorkH < 0)
    {
	vals->WorkH = SW_WorkWindow(w) ? XtHeight(SW_WorkWindow(w)) : 0;
    }
    if (vals->WorkW < 0)
    {
	vals->WorkW = SW_WorkWindow(w) ? XtWidth(SW_WorkWindow(w)) : 0;
    }
    if (vals->VsbH < 0)
    {
	vals->VsbH = SW_VSB(w) ? XtHeight(SW_VSB(w)) : 0;
    }
    if (vals->VsbW < 0)
    {
	vals->VsbW = SW_VSB(w) ? XtWidth(SW_VSB(w)) : 0;
    }
    if (vals->HsbH < 0)
    {
	vals->HsbH = SW_HSB(w) ? XtHeight(SW_HSB(w)) : 0;
    }
    if (vals->HsbW < 0)
    {
	vals->HsbW = SW_HSB(w) ? XtWidth(SW_HSB(w)) : 0;
    }

    if (child)
    {
	if (child == MW_MenuBar(w))
	{
	    cg->x = vals->mbx;
	    cg->y = vals->mby;
	    cg->width = vals->mbw < 0 ? XtWidth(child) : vals->mbw;
	    cg->height = vals->mbh < 0 ? XtHeight(child) : vals->mbh;
	    cg->request_mode = CWWidth | CWHeight | CWX | CWY;
	}
	else if (child == MW_CommandWindow(w))
	{
	    cg->x = vals->cwx;
	    cg->y = vals->cwy;
	    cg->width = vals->cww < 0 ? XtWidth(child) : vals->cww;
	    cg->height = vals->cwh < 0 ? XtHeight(child) : vals->cwh;
	    cg->request_mode = CWWidth | CWHeight | CWX | CWY;
	}
	else if (child == MW_MessageWindow(w))
	{
	    cg->x = vals->mwx;
	    cg->y = vals->mwy;
	    cg->width = vals->mww < 0 ? XtWidth(child) : vals->mww;
	    cg->height = vals->mwh < 0 ? XtHeight(child) : vals->mwh;
	    cg->request_mode = CWWidth | CWHeight | CWX | CWY;
	}
	else if (child == (Widget)MW_Sep1(w))
	{
	    cg->x = vals->s1x;
	    cg->y = vals->s1y;
	    cg->width = vals->s1w < 0 ? XtWidth(child) : vals->s1w;
	    cg->height = vals->s1h < 0 ? XtHeight(child) : vals->s1h;
	    cg->request_mode = CWWidth | CWHeight | CWX | CWY;
	}
	else if (child == (Widget)MW_Sep2(w))
	{
	    cg->x = vals->s2x;
	    cg->y = vals->s2y;
	    cg->width = vals->s2w < 0 ? XtWidth(child) : vals->s2w;
	    cg->height = vals->s2h < 0 ? XtHeight(child) : vals->s2h;
	    cg->request_mode = CWWidth | CWHeight | CWX | CWY;
	}
	else if (child == (Widget)MW_Sep3(w))
	{
	    cg->x = vals->s3x;
	    cg->y = vals->s3y;
	    cg->width = vals->s3w < 0 ? XtWidth(child) : vals->s3w;
	    cg->height = vals->s3h < 0 ? XtHeight(child) : vals->s3h;
	    cg->request_mode = CWWidth | CWHeight | CWX | CWY;
	}
	else if (child == (Widget)SW_WorkWindow(w))
	{
	    cg->request_mode = CWX | CWY | CWHeight | CWWidth;
	    cg->x = vals->WorkX;
	    cg->y = vals->WorkY;
	    cg->width = vals->WorkW;
	    cg->height = vals->WorkH;
	}
	else if (child == (Widget)SW_ClipWindow(w))
	{
	    cg->request_mode = CWX | CWY | CWHeight | CWWidth;
	    cg->x = vals->ClipX;
	    cg->y = vals->ClipY;
	    cg->width = vals->ClipW;
	    cg->height = vals->ClipH;
	}
	else if (child == (Widget)SW_HSB(w))
	{
	    cg->request_mode = CWX | CWY | CWHeight | CWWidth;
	    cg->x = vals->HsbX;
	    cg->y = vals->HsbY;
	    cg->width = vals->HsbW;
	    cg->height = vals->HsbH;
	}
	else if (child == (Widget)SW_VSB(w))
	{
	    cg->request_mode = CWX | CWY | CWHeight | CWWidth;
	    cg->x = vals->VsbX;
	    cg->y = vals->VsbY;
	    cg->width = vals->VsbW;
	    cg->height = vals->VsbH;
	}

	DEBUGOUT(XdbDebug2(__FILE__, w, child, "feedback => %s\n",
			   XdbWidgetGeometry2String(cg)));
    }
}


/* Configure the children, or return their geometry if they're the instigator */
#define	CONF(wid, xx, yy, ww, hh)					\
    {									\
	DEBUGOUT(XdbDebug2(__FILE__, w, wid,                            \
                           "CONF: x %d y %d w %d h %d\n",               \
			   xx, yy, ww, hh));				\
	if (child && wid == child)					\
	{								\
	    XtX(wid) = cg->x;						\
	    XtY(wid) = cg->x;						\
	    XtWidth(wid) = cg->width;					\
	    XtHeight(wid) = cg->height;					\
	}								\
	else								\
	{								\
	    _XmConfigureObject(wid, xx, yy, ww, hh, XtBorderWidth(wid));\
	}								\
    }

static void
_XmMainWindowConfigureChildren(Widget w, Widget child,
			       XtWidgetGeometry *cg, XmMWValues *vals)
{
    if (VALID(MW_MenuBar(w)))
    {
	CONF(MW_MenuBar(w), vals->mbx, vals->mby, vals->mbw, vals->mbh);
    }
    if (MW_ShowSep(w) && VALID(MW_Sep1(w)))
    {
	CONF((Widget)MW_Sep1(w), vals->s1x, vals->s1y, vals->s1w, vals->s1h);
    }
    if (VALID(MW_CommandWindow(w)))
    {
	CONF(MW_CommandWindow(w), vals->cwx, vals->cwy, vals->cww, vals->cwh);
    }
    if (MW_ShowSep(w) && VALID(MW_Sep2(w)))
    {
	CONF((Widget)MW_Sep2(w), vals->s2x, vals->s2y, vals->s2w, vals->s2h);
    }
    if (VALID(MW_MessageWindow(w)))
    {
	CONF(MW_MessageWindow(w), vals->mwx, vals->mwy, vals->mww, vals->mwh);
    }
    if (MW_ShowSep(w) && VALID(MW_Sep3(w)))
    {
	CONF((Widget)MW_Sep3(w), vals->s3x, vals->s3y, vals->s3w, vals->s3h);
    }

    if (XdbInDebug(__FILE__, w))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "_XmMainWConfigureChildren: Sw %dx%d\n",
			  vals->www, vals->wwh));
	DEBUGOUT(XdbDebug0(__FILE__, w,
			   "\t\tX\tY\tW\tH\n\tWork\t%d\t%d\t%d\t%d\n",
			   vals->WorkX, vals->WorkY, vals->WorkW, vals->WorkH));
	DEBUGOUT(XdbDebug0(__FILE__, w,
			   "\tClip\t%d\t%d\t%d\t%d\n",
			   vals->ClipX, vals->ClipY, vals->ClipW, vals->ClipH));
	DEBUGOUT(XdbDebug0(__FILE__, w,
			   "\tHsb\t%d\t%d\t%d\t%d\t%3s managed\n",
			   vals->HsbX, vals->HsbY, vals->HsbW, vals->HsbH,
			   (vals->ShowHSB && vals->HasHSB) ? "" : "not"));
	DEBUGOUT(XdbDebug0(__FILE__, w,
			   "\tVsb\t%d\t%d\t%d\t%d\t%3s managed\n",
			   vals->VsbX, vals->VsbY, vals->VsbW, vals->VsbH,
			   (vals->ShowVSB && vals->HasVSB) ? "" : "not"));
    }

    _XmConfigureScrollBars(w, child, cg, (XmSWValues *)vals);

    if (SW_ClipWindow(w))
    {
	if (child == (Widget)SW_ClipWindow(w))
	{
	    XtX(SW_ClipWindow(w)) = vals->ClipX;
	    XtY(SW_ClipWindow(w)) = vals->ClipY;
	    XtWidth(SW_ClipWindow(w)) = vals->ClipW;
	    XtHeight(SW_ClipWindow(w)) = vals->ClipH;
	}
	else
	{
	    _XmConfigureObject((Widget)SW_ClipWindow(w),
			       vals->ClipX, vals->ClipY,
			       vals->ClipW, vals->ClipH,
			       XtBorderWidth(SW_ClipWindow(w)));
	}

	SW_CWX(w) = vals->ClipX;
	SW_CWY(w) = vals->ClipY;
	SW_CWWidth(w) = vals->ClipW;
	SW_CWHeight(w) = vals->ClipH;
    }

    if (SW_WorkWindow(w))
    {
	if (child == SW_WorkWindow(w))
	{
	    XtX(SW_WorkWindow(w)) = vals->WorkX;
	    XtY(SW_WorkWindow(w)) = vals->WorkY;
	    XtWidth(SW_WorkWindow(w)) = vals->WorkW;
	    XtHeight(SW_WorkWindow(w)) = vals->WorkH;
	}
	else
	{
	    _XmConfigureObject(SW_WorkWindow(w),
			       vals->WorkX, vals->WorkY,
			       vals->WorkW, vals->WorkH,
			       XtBorderWidth(SW_WorkWindow(w)));
	}

	if (SW_ScrollPolicy(w) != XmAUTOMATIC)
	{
	    SW_CWX(w) = vals->ClipX;
	    SW_CWY(w) = vals->ClipY;
	    SW_CWWidth(w) = vals->ClipW;
	    SW_CWHeight(w) = vals->ClipH;
	}
    }

    if (SW_ScrollPolicy(w) == XmAUTOMATIC)
    {
	_XmFixupScrollBars(w, vals->WorkW, vals->WorkH);
	_XmRepositionScrolledWindow((Widget)SW_ClipWindow(w), NULL, NULL);
    }
}

static XtGeometryResult
geometry_manager(Widget w,
		 XtWidgetGeometry *desired,
		 XtWidgetGeometry *allowed)
{
    XmMWValues vals;
    XtWidgetGeometry wants;

    DEBUGOUT(XdbDebug2(__FILE__, XtParent(w), w,
		       "geometry_manager request %s\n",
		       XdbWidgetGeometry2String(desired)));

#define Wants(flag)     (wants.request_mode & flag)

    wants = *desired;

    if (Wants(XtCWQueryOnly))
    {
	DEBUGOUT(XdbDebug(__FILE__, w,
			  "Geometry Mgr Query Only Unimplemented\n"));
	return XtGeometryYes;
    }
    if (Wants(CWX) || Wants(CWY))
	return XtGeometryNo;

    /*
     * We control the XY of all children.  Width/Height is all I care about
     */
    _XmMainWindowPreferredSize(XtParent(w), w, &wants, &vals);

    /* FIX ME: Pay attention to return code? */
    if (_XmMainWindowGeomRequest(XtParent(w), &vals) == XtGeometryYes)
    {
	_XmMainWindowLayout(XtParent(w), w, &wants, &vals);
    }
    else
    {
	vals.MwW = XtWidth(XtParent(w));
	vals.MwH = XtHeight(XtParent(w));
	_XmMainWindowLayout(XtParent(w), w, &wants, &vals);
    }

    wants.request_mode = desired->request_mode & (CWWidth | CWHeight);

    *allowed = wants;

    if (Wants((CWWidth | CWHeight)) == (CWWidth | CWHeight) &&
	wants.width == desired->width && wants.height == desired->height)
    {
	_XmMainWindowConfigureChildren(XtParent(w), w, &wants, &vals);

	return XtGeometryYes;
    }
    else if (Wants((CWWidth | CWHeight)) == CWWidth &&
	     wants.width == desired->width)
    {
	_XmMainWindowConfigureChildren(XtParent(w), w, &wants, &vals);

	return XtGeometryYes;
    }
    else if (Wants((CWWidth | CWHeight)) == CWHeight &&
	     wants.height == desired->height)
    {
	_XmMainWindowConfigureChildren(XtParent(w), w, &wants, &vals);

	return XtGeometryYes;
    }

    /*
     * Try this : if we have a difference, just report "Almost"
     */
    DEBUGOUT(XdbDebug2(__FILE__, XtParent(w), w,
		       "geometry_manager : child wants %s gets %s => Almost\n",
		       XdbWidgetGeometry2String(&wants),
		       XdbWidgetGeometry2String(desired)));

    return XtGeometryAlmost;
#undef	Wants
}

Widget
XmCreateMainWindow(Widget parent,
		   char *name,
		   Arg *argList,
		   Cardinal argcount)
{
    return XtCreateWidget(name,
			  xmMainWindowWidgetClass,
			  parent,
			  argList, argcount);

}

Widget
XmMainWindowSep1(Widget widget)
{
    return (Widget)MW_Sep1(widget);
}

Widget
XmMainWindowSep2(Widget widget)
{
    return (Widget)MW_Sep2(widget);
}

Widget
XmMainWindowSep3(Widget widget)
{
    return (Widget)MW_Sep3(widget);
}

void
XmMainWindowSetAreas(Widget widget,
		     Widget menu_bar,
		     Widget command_window,
		     Widget horizontal_scrollbar,
		     Widget vertical_scrollbar,
		     Widget work_region)
{
    /* color computation */
    XColor _widgetBackground;
    XColor troughColor;
 
    DEBUGOUT(XdbDebug(__FILE__, widget, "XmMainWindowSetAreas ["));

#define	P(cw, t)						\
    if (cw)							\
	DEBUGOUT(XdbDebug0(__FILE__, widget, t, XtName(cw)));	\
    else							\
	DEBUGOUT(XdbDebug0(__FILE__, widget, t, ": NULL"));

    P(menu_bar, " MenuBar %s");
    P(command_window, " CommandWindow %s");
    P(horizontal_scrollbar, " Hor.Scrollbar %s");
    P(vertical_scrollbar, " Vert.Scrollbar %s");
    P(work_region, " WorkRegion %s");
    DEBUGOUT(XdbDebug0(__FILE__, widget, "]\n"));

    if (menu_bar)
    {
	MW_MenuBar(widget) = menu_bar;

	if (menu_bar == MW_MessageWindow(widget))
	{
	    MW_MessageWindow(widget) = NULL;
	}
    }
    if (command_window)
    {
	MW_CommandWindow(widget) = command_window;
	if (command_window == MW_MessageWindow(widget))
	{
	    MW_MessageWindow(widget) = NULL;
	}
    }
    if (work_region)
    {
	SW_WorkWindow(widget) = work_region;
	if (work_region == MW_MessageWindow(widget))
	{
	    MW_MessageWindow(widget) = NULL;
	}
    }
    if (horizontal_scrollbar)
    {
	SW_HSB(widget) = (XmScrollBarWidget)horizontal_scrollbar;
	if (horizontal_scrollbar == MW_MessageWindow(widget))
	{
	    MW_MessageWindow(widget) = NULL;
	}
    }
    if (vertical_scrollbar)
    {
	SW_VSB(widget) = (XmScrollBarWidget)vertical_scrollbar;
	if (vertical_scrollbar == MW_MessageWindow(widget))
	{
	    MW_MessageWindow(widget) = NULL;
	}
    }

    if (horizontal_scrollbar || vertical_scrollbar)
    {
	_widgetBackground.pixel = XtBackground(widget);
 
	XQueryColor(XtDisplay(widget),
		    DefaultColormapOfScreen(XtScreen(widget)),
		    &_widgetBackground);
 
	troughColor.blue = _widgetBackground.blue * .80;
	troughColor.green = _widgetBackground.green * .80;
	troughColor.red = _widgetBackground.red * .80;
 
	if (!XAllocColor(XtDisplay(widget),
			 DefaultColormapOfScreen(XtScreen(widget)),
			 &troughColor))
	{
	    troughColor.pixel =
		WhitePixelOfScreen(DefaultScreenOfDisplay(XtDisplay(widget)));
	}
    }

    if (horizontal_scrollbar)
    {
	XtVaSetValues(horizontal_scrollbar,
		      XmNforeground, MGR_Foreground(widget),
		      XmNbackground, XtBackground(widget),
		      XmNtroughColor, troughColor.pixel,
		      XmNtopShadowColor, MGR_TopShadowColor(widget),
		      XmNtopShadowPixmap, MGR_TopShadowPixmap(widget),
		      XmNbottomShadowColor, MGR_BottomShadowColor(widget),
		      XmNbottomShadowPixmap, MGR_BottomShadowPixmap(widget),
		      NULL);
    }
    if (vertical_scrollbar)
    {
	XtVaSetValues(vertical_scrollbar,
		      XmNforeground, MGR_Foreground(widget),
		      XmNbackground, XtBackground(widget),
		      XmNtroughColor, troughColor.pixel,
		      XmNtopShadowColor, MGR_TopShadowColor(widget),
		      XmNtopShadowPixmap, MGR_TopShadowPixmap(widget),
		      XmNbottomShadowColor, MGR_BottomShadowColor(widget),
		      XmNbottomShadowPixmap, MGR_BottomShadowPixmap(widget),
		      NULL);
    }

#if 0
    if (XtIsRealized(widget))
    {
	XmMWValues vals;

	_XmMainWindowPreferredSize(widget, NULL, NULL, &vals);

	_XmMainWindowGeomRequest(widget, &vals);

	_XmMainWindowLayout(widget, NULL, NULL, &vals);

	_XmMainWindowConfigureChildren(widget, NULL, NULL, &vals);
    }
#endif
}

static void
insert_child(Widget w)
{
    Widget p = XtParent(w);

    if ((XmIsRowColumn(w) && RC_Type(w) == XmMENU_BAR) ||
	XmIsSeparator(w) || XmIsSeparatorGadget(w))
    {
#define	superclass	(&xmManagerClassRec)
	(*superclass->composite_class.insert_child) (w);
#undef	superclass

	if (XmIsRowColumn(w) && RC_Type(w) == XmMENU_BAR)
	{
	    DEBUGOUT(XdbDebug2(__FILE__, p, w,
			       "insert_child : this is the menu bar\n"));
	    MW_MenuBar(p) = w;
	}
	else if (XmIsSeparator(w) || XmIsSeparatorGadget(w))
	{
	    DEBUGOUT(XdbDebug2(__FILE__, p, w,
			       "insert_child : this is a separator\n"));
	}
	else if (MW_MessageWindow(p) == NULL &&
	    w != MW_CommandWindow(p) &&
	    w != MW_MenuBar(p) &&
	    w != SW_WorkWindow(p) &&
	    w != (Widget)SW_ClipWindow(p) &&
	    w != (Widget)SW_HSB(p) &&
	    w != (Widget)SW_VSB(p))
	{
	    DEBUGOUT(XdbDebug2(__FILE__, p, w,
			       "insert_child : this is the message window\n"));
	    MW_MessageWindow(p) = w;
	}
    }
    else
    {
	/* 
	 * Now we have a scrollbar or a workwindow - let scrolledwindow
	 * handle this
	 */
#define	superclass	(&xmScrolledWindowClassRec)
	(*superclass->composite_class.insert_child) (w);
#undef	superclass

	if (MW_MessageWindow(p) == NULL &&
	    w != MW_CommandWindow(p) &&
	    w != MW_MenuBar(p) &&
	    w != SW_WorkWindow(p) &&
	    w != (Widget)SW_ClipWindow(p) &&
	    w != (Widget)SW_HSB(p) &&
	    w != (Widget)SW_VSB(p))
	{
	    DEBUGOUT(XdbDebug2(__FILE__, p, w,
			       "insert_child : this is the message window\n"));
	    MW_MessageWindow(p) = w;
	}
    }
}
