/* 
 *  @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: ScrolledW.c /main/16 1997/07/25 16:49:57 samborn $"
#endif
#endif
/* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */

#ifndef X_NOT_STDC_ENV
#include <stdlib.h>    /* for abs, float operation... */
#endif

#include <Xm/ClipWindowP.h>
#include <Xm/DragDrop.h>
#include <Xm/DrawP.h>
#include <Xm/NavigatorT.h>
#include <Xm/ScrollBarP.h>	/* might be worth getting rid of this one */
#include <Xm/TraitP.h>
#include <Xm/TransltnsP.h>
#include "GeoUtilsI.h"
#include "MessagesI.h"
#include "RepTypeI.h"
#include "ScrolledWI.h"
#include "ScrollFramTI.h"
#include "TraversalI.h"
#include "XmI.h"


#define MAXPOS ((1 << 15)-1)


#define SB_BORDER_WIDTH 0
#define DEFAULT_SPACING 4
#define DEFAULT_SIZE 100
#define ExistManaged( wid)      (wid && XtIsManaged( wid))
#define defaultTranslations	_XmScrolledW_ScrolledWindowXlations

/* Auto drag private ********/

#define FORWARD 0
#define BACKWARD 1

typedef struct _AutoDragClosure
{  Widget widget;
   unsigned char direction ;
} AutoDragClosure;

typedef struct _AutoDragRects
{
  XRectangle up;
  XRectangle left;
} AutoDragRectsRec, *AutoDragRects;

#define POINT_IN_RECT(X, Y, rect) \
    (((X) >= rect.x) && ((Y) >= rect.y) && \
     ((X) <= rect.x + rect.width) && ((Y) <= rect.y + rect.height))

/*********/


#define SWMessage6	_XmMMsgScrolledW_0004
#define SWMessage7	_XmMMsgScrolledW_0005
#define SWMessage8	_XmMMsgScrolledW_0006
#define SWMessage9	_XmMMsgScrolledW_0007
#define SWMessage10	_XmMMsgScrolledW_0008
#define SWMessage11	_XmMMsgScrolledW_0009

/********    Static Function Declarations    ********/

static void ScrollBarPlacementDefault (
			Widget w, 
			int offset, 
			XrmValue *value);
static void VisualPolicyDefault( 
                        Widget widget,
                        int offset,
                        XrmValue *value) ;
static void SliderMove( 
                        Widget w,
                        XtPointer closure,
                        XtPointer cd) ;
static void MoveWindow(    
		        XmScrolledWindowWidget sw,
		        int value,
		        unsigned char direction) ;
static void LeftEdge( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void RightEdge( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void TopEdge( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void BottomEdge( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void PageLeft( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void PageRight( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void PageUp( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void PageDown( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;

static void ClassPartInitialize( 
                        WidgetClass wc) ;
static void Initialize( 
                        Widget rw,
                        Widget nw,
                        ArgList args,
                        Cardinal *num_args) ;
static void Redisplay( 
                        Widget wid,
                        XEvent *event,
                        Region region) ;
static void ComputeLocations(
			XmScrolledWindowWidget sw,
			Dimension HSBht, Dimension VSBht,
        		Boolean HasHSB, Boolean HasVSB,
			Position * newx, Position * newy,
			Position * hsbX, Position * hsbY,
 			Position * vsbX, Position * vsbY);
static void VariableLayout( 
                        XmScrolledWindowWidget sw) ;
static void ConstantLayout( 
                        XmScrolledWindowWidget sw) ;
static void Resize( 
                        Widget wid) ;
static void Destroy( 
                        Widget wid) ;
static void GetVariableSize( 
                        XmScrolledWindowWidget sw,
	                Dimension *pwidth,
                        Dimension *pheight) ;
static XtGeometryResult GeometryManager( 
                        Widget w,
                        XtWidgetGeometry *request,
                        XtWidgetGeometry *reply) ;
static void ChangeManaged( 
                        Widget wid) ;
static void InsertChild( 
                        Widget w) ;
static void DeleteChild( 
                        Widget w) ;
static XtGeometryResult QueryGeometry( 
                        Widget wid,
                        XtWidgetGeometry *request,
                        XtWidgetGeometry *ret) ;
static Boolean SetValues( 
                        Widget cw,
                        Widget rw,
                        Widget nw,
                        ArgList args,
                        Cardinal *num_args) ;
static void ConstraintInitialize(
                        Widget rw,
                        Widget nw,
                        ArgList args,
                        Cardinal *num_args) ;
static void GetHorRects(
			Widget sw,
			XRectangle ** hrect, 
			Cardinal * num_hrect);
static void GetVertRects(
			Widget sw,
			XRectangle ** vrect, 
			Cardinal * num_vrect);

static void HandleDrop(
		       Widget		w,
		       XtPointer	client_data, 
		       XtPointer	call_data);
static void HandleDrag(
		       Widget		w,
		       XtPointer	client_data, 
		       XtPointer	call_data);


static void ScrollFrameInit (
			     Widget sf, 
			     XtCallbackProc moveCB,
			     Widget scrollable);
static Boolean  GetInfo(
			Widget sf,
			Cardinal * dimension,
			Widget ** nav_list,
			Cardinal * num_nav_list) ;
static void AddNavigator(
		       Widget sf,
		       Widget nav,
		       Mask dimMask);
static void RemoveNavigator(
		       Widget sf,
		       Widget nav);
static void UpdateOrigGeom(Widget sf, 
			   Widget child,
			   XtWidgetGeometry *geom);

static void CheckKids(
			XmScrolledWindowWidget sw);


/********    End Static Function Declarations    ********/




/************************************************************************
 *									*
 * Scrolled Window Resources						*
 *									*
 ************************************************************************/

static XtResource resources[] = 
{
	  
    {
	XmNhorizontalScrollBar, XmCHorizontalScrollBar, 
	XmRWidget, sizeof(Widget),
        XtOffsetOf(XmScrolledWindowRec, swindow.hScrollBar),
	XmRImmediate, NULL
    },
    {
	XmNverticalScrollBar, XmCVerticalScrollBar, XmRWidget, sizeof(Widget),
        XtOffsetOf(XmScrolledWindowRec, swindow.vScrollBar),
	XmRImmediate, NULL
    },
    {
	XmNworkWindow, XmCWorkWindow, XmRWidget, sizeof(Widget),
        XtOffsetOf(XmScrolledWindowRec, swindow.WorkWindow),
	XmRImmediate, NULL
    },
    {
	XmNclipWindow, XmCClipWindow, XmRWidget, sizeof(Widget),
        XtOffsetOf(XmScrolledWindowRec, swindow.ClipWindow),
	XmRImmediate, NULL
    },
    {
        XmNscrollingPolicy, XmCScrollingPolicy, XmRScrollingPolicy, 
	sizeof(unsigned char),
        XtOffsetOf(XmScrolledWindowRec, swindow.ScrollPolicy),
        XmRImmediate, (XtPointer)  XmAPPLICATION_DEFINED
    },   
    {
	/* Obsolete resource */
        XmNvisualPolicy, XmCVisualPolicy, XmRVisualPolicy, 
	sizeof (unsigned char),
        XtOffsetOf(XmScrolledWindowRec, swindow.VisualPolicy),
        XmRCallProc,  (XtPointer) VisualPolicyDefault
    },   
    {
        XmNscrollBarDisplayPolicy, XmCScrollBarDisplayPolicy, 
	XmRScrollBarDisplayPolicy, sizeof (char),
        XtOffsetOf(XmScrolledWindowRec, swindow.ScrollBarPolicy),
        XmRImmediate,  (XtPointer) RESOURCE_DEFAULT
    },   
    {
        XmNscrollBarPlacement, XmCScrollBarPlacement, XmRScrollBarPlacement, 
	sizeof (unsigned char),
        XtOffsetOf(XmScrolledWindowRec, swindow.Placement),
        XmRCallProc, (XtPointer) ScrollBarPlacementDefault
   },

    {
        XmNscrolledWindowMarginWidth, XmCScrolledWindowMarginWidth,
        XmRHorizontalDimension, sizeof (Dimension), 
        XtOffsetOf(XmScrolledWindowRec, swindow.WidthPad), 
	XmRImmediate, (XtPointer) 0
    },
    {   
        XmNscrolledWindowMarginHeight, XmCScrolledWindowMarginHeight, 
        XmRVerticalDimension, sizeof (Dimension), 
        XtOffsetOf(XmScrolledWindowRec, swindow.HeightPad), 
	XmRImmediate, (XtPointer) 0
    },

    {
        XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof (Dimension),
        XtOffsetOf(XmScrolledWindowRec, swindow.pad),
        XmRImmediate,  (XtPointer) RESOURCE_DEFAULT
    },

    {
        XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, 
        sizeof (Dimension),
        XtOffsetOf(XmScrolledWindowRec, manager.shadow_thickness),
        XmRImmediate,  (XtPointer) RESOURCE_DEFAULT
    },
    {
        XmNtraverseObscuredCallback, XmCCallback, XmRCallback,
        sizeof(XtCallbackList),
        XtOffsetOf(XmScrolledWindowRec, swindow.traverseObscuredCallback),
        XmRImmediate, NULL
    },
    {
        XmNautoDragModel, XmCAutoDragModel, XmRAutoDragModel,
        sizeof(XtEnum),
        XtOffsetOf(XmScrolledWindowRec, swindow.auto_drag_model),
        XmRImmediate, (XtPointer) XmAUTO_DRAG_ENABLED
    }
};


static XtResource constraints[] =
{
   {  XmNscrolledWindowChildType, XmCScrolledWindowChildType,
      XmRScrolledWindowChildType,
      sizeof (unsigned char),
      XtOffsetOf(XmScrolledWindowConstraintRec, swindow.child_type),
      XmRImmediate, (XtPointer) RESOURCE_DEFAULT },
};


/****************
 *
 * Resolution independent resources
 *
 ****************/

static XmSyntheticResource syn_resources[] =
{
   { XmNscrolledWindowMarginWidth, 
     sizeof (Dimension),
     XtOffsetOf(XmScrolledWindowRec, swindow.WidthPad), 
     XmeFromHorizontalPixels,
     XmeToHorizontalPixels },

   { XmNscrolledWindowMarginHeight, 
     sizeof (short),
     XtOffsetOf(XmScrolledWindowRec, swindow.HeightPad),
     XmeFromVerticalPixels,
     XmeToVerticalPixels },

   { XmNspacing, 
     sizeof (Dimension),
     XtOffsetOf(XmScrolledWindowRec, swindow.pad), 
     XmeFromHorizontalPixels ,
     XmeToHorizontalPixels },

};

/****************
 * Actions for the ScrolledWindow.
 * Those actions are called by the ClipWindow when it receives
 * the grabbed events. They might also be called in the context of the 
 * SW directly (in the margins).
 ****************/
 
static XtActionsRec actions[] =
{
 {"SWBeginLine",        LeftEdge},
 {"SWEndLine",          RightEdge},
 {"SWTopLine",          TopEdge},
 {"SWBottomLine",       BottomEdge},
 {"SWLeftPage",         PageLeft},
 {"SWRightPage",        PageRight},
 {"SWUpPage",           PageUp},
 {"SWDownPage",         PageDown}, 
};

/*******************************************/
/*  Declaration of class extension records */
/*******************************************/

static XmScrolledWindowClassExtRec scrolled_windowClassExtRec = {
    NULL,
    NULLQUARK,
    XmScrolledWindowClassExtVersion,
    sizeof(XmScrolledWindowClassExtRec),
    GetHorRects,                       /* auto drag get_hor_rects */
    GetVertRects,                      /* auto drag get_vert_rects */
};


/****************************************************************
 *
 * Full class record constant
 *
 ****************************************************************/

externaldef(xmscrolledwindowclassrec) XmScrolledWindowClassRec 
        xmScrolledWindowClassRec = {
  {
/* core_class fields      */
    /* superclass         */    (WidgetClass) &xmManagerClassRec,
    /* class_name         */    "XmScrolledWindow",
    /* widget_size        */    sizeof(XmScrolledWindowRec),
    /* class_initialize   */    NULL,
    /* class_partinit     */    ClassPartInitialize,
    /* class_inited       */	FALSE,
    /* initialize         */    Initialize,
    /* Init hook	  */    NULL,
    /* realize            */    XtInheritRealize,
    /* actions		  */	actions,
    /* num_actions	  */	XtNumber(actions),
    /* resources          */    resources,
    /* num_resources      */    XtNumber(resources),
    /* xrm_class          */    NULLQUARK,
    /* compress_motion	  */	TRUE,
    /* compress_exposure  */	XtExposeCompressMaximal,
    /* compress_enterleave*/	TRUE,
    /* visible_interest   */    FALSE,
    /* destroy            */    Destroy,
    /* resize             */    Resize,
    /* expose             */    Redisplay,
    /* set_values         */    SetValues,
    /* set values hook    */    (XtArgsFunc)NULL,
    /* set values almost  */    XtInheritSetValuesAlmost,
    /* get values hook    */    NULL,
    /* accept_focus       */    NULL,
    /* Version            */    XtVersion,
    /* PRIVATE cb list    */    NULL,
    /* tm_table		  */    XtInheritTranslations,
    /* query_geometry     */    QueryGeometry,
    /* display_accelerator*/    NULL,
    /* extension          */    NULL,
  },
  {
/* composite_class fields */
    /* geometry_manager   */    GeometryManager,
    /* change_managed     */    ChangeManaged,
    /* insert_child	  */	InsertChild,	
    /* delete_child	  */	DeleteChild,	
    /* Extension          */    NULL,
  },{
/* Constraint class Init */
    constraints,				/* resource list        */   
    XtNumber(constraints),			/* num resources        */   
    sizeof (XmScrolledWindowConstraintRec),     /* constraint size      */   
    ConstraintInitialize,			/* init proc            */   
    NULL,			                /* destroy proc         */   
    NULL,			                /* set values proc      */   
    NULL,
  },
/* Manager Class */
   {		
      defaultTranslations,	                /* translations        */    
      syn_resources,				/* get resources      	  */
      XtNumber(syn_resources),			/* num syn_resources 	  */
      NULL,					/* get_cont_resources     */
      0,					/* num_get_cont_resources */
      XmInheritParentProcess,                   /* parent_process         */
      NULL,					/* extension           */    
   },

 {
/* Scrolled Window class */     
    (XtPointer) &scrolled_windowClassExtRec,    /* auto drag extension */
 }
};

externaldef(xmscrolledwindowwidgetclass) WidgetClass 
    xmScrolledWindowWidgetClass = (WidgetClass)&xmScrolledWindowClassRec;


/* Trait record for ScrolledWindow */

static XmConst XmScrollFrameTraitRec scrolledWindowSFT = {
    1,				/* version	   */
    ScrollFrameInit,		/* init		   */
    GetInfo,			/* getInfo	   */
    AddNavigator,		/* addNavigation   */
    RemoveNavigator,		/* removeNavigator */
    UpdateOrigGeom,		/* updateOrigGeom */
};



/*********************************************************************
 *
 * ScrollBarPlacementDefault
 *    This procedure provides the dynamic default behavior for
 *    the scrollbar placement.
 *
 *********************************************************************/

/*ARGSUSED*/
static void 
ScrollBarPlacementDefault (Widget widget,
			   int offset, /* unused */
			   XrmValue *value)
{
  static unsigned char placement;
  
  value->addr = (char*) &placement;
  
  if (LayoutIsRtoLM(((XmScrolledWindowWidget)widget)))
    placement = XmBOTTOM_LEFT;
  else
    placement = XmBOTTOM_RIGHT;

}


/*********************************************************************
 *
 * VisualPolicyDefault
 *    This procedure provides the dynamic default behavior for 
 *    the visualPolicy. VisualPolicy is obsolete, the default set it
 *    to whatever is correct (depending on scrollpolicy) and Initialize
 *    checks that this default hasn't changed.
 *
 *********************************************************************/
/*ARGSUSED*/
static void 
VisualPolicyDefault(
        Widget widget,
        int offset,		/* unused */
        XrmValue *value )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) widget;
    static unsigned char visual_policy ; 

    value->addr = (XPointer) &visual_policy;
              
    if (sw->swindow.ScrollPolicy == XmAUTOMATIC)
	visual_policy = XmCONSTANT ;
    else
	visual_policy = XmVARIABLE ;
}




/************************************************************************
 *									*
 *  SliderMove							        *
 *  Callback for the value changes of navigators.	                *
 *  That's the only place where AUTO scrolledWindow directly moves      *
 *   the clipped kids. Everywhere it uses the navigator API to move it.       
 *  This function loops the clip window child list and applies a 
 *   move depending on the child_type resource.
 *
 ************************************************************************/
/* ARGSUSED */
static void
SliderMove(
        Widget w,
        XtPointer closure,
        XtPointer cd )
{
    /* w is a navigator widget */

    XmClipWindowWidget clip = (XmClipWindowWidget) closure;
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) clip->core.parent;
    Cardinal i ;
    XmScrolledWindowConstraint swc;
    Widget child ;
    XmNavigatorDataRec nav_data ;

    /* get the navigator information using the trait getValue since I
       cannot use a callback struct */

    nav_data.valueMask = NavValue ;
    ((XmNavigatorTrait)XmeTraitGet((XtPointer) XtClass(w), XmQTnavigator))
	->getValue(w, &nav_data) ;
    

    /* look at the kind of navigator and make the appropriate move */

    if (nav_data.dimMask & NavigDimensionX) {
	sw->swindow.hOrigin = nav_data.value.x;

	for (i = 0; i < clip->composite.num_children; i++) {
	    child = clip->composite.children[i];
	    if (XtIsManaged(child) && !child->core.being_destroyed) {
		swc = GetSWConstraint(child);

		/* only regular work_area and scroll_hor kids 
		   can move in this direction */
		if ((swc->child_type == XmWORK_AREA) ||
		    (swc->child_type == XmSCROLL_HOR)) {
		    Position real_orig_x ;

		    if (LayoutIsRtoL((Widget)sw))
			real_orig_x = clip->core.width - swc->orig_x 
			    - child->core.width;
		    else 
			real_orig_x = swc->orig_x ;	

		    if (LayoutIsRtoLM(sw)) 
			XmeConfigureObject(child, 
					   real_orig_x + nav_data.value.x, 
					   child->core.y,
					   child->core.width, 
					   child->core.height,
					   child->core.border_width);
		    else
			XmeConfigureObject(child, 
					   swc->orig_x - nav_data.value.x, 
					   child->core.y,
					   child->core.width, 
					   child->core.height,
					   child->core.border_width);
		} 	 
	    }
	}
    } 

    if (nav_data.dimMask & NavigDimensionY) {
	sw->swindow.vOrigin = nav_data.value.y;

	for (i = 0; i < clip->composite.num_children; i++) {
	    child = clip->composite.children[i];
	    if (XtIsManaged(child) && !child->core.being_destroyed) {
		swc = GetSWConstraint(child);
	
		/* only regular work_area and scroll_vert kids 
		   can move in this direction */
		if ((swc->child_type == XmWORK_AREA) ||
		    (swc->child_type == XmSCROLL_VERT)) {
		    XmeConfigureObject(child, child->core.x, 
				       swc->orig_y - nav_data.value.y,
				       child->core.width, 
				       child->core.height,
				       child->core.border_width);
		} 	
	    }
	}
    } 

    /* now update the other navigator value */
    _XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, False);
	
}



/************************************************************************
 *									*
 *  MoveWindow	: called for paging only		                *
 *       Set the scrollbar (h or v) value and move the workwindow       *
 *		using the sb callback and deal with traversal           *
 *									*
 ************************************************************************/
static void 
MoveWindow(    
        XmScrolledWindowWidget sw,
        int value,
        unsigned char orientation)
{
    Widget focus ;
    XtCallbackList tmp ;
    XmNavigatorDataRec nav_data ;

    if (sw->swindow.ScrollPolicy == XmAUTOMATIC) {

	/* Save the focus before pagin.bg */
	focus = XmGetFocusWidget((Widget) sw);

	/* possible value for orientation: horizontal or vertical */
	if (orientation == XmHORIZONTAL) {
	    nav_data.value.x = value ;
	    nav_data.dimMask = NavigDimensionX ;
	} else  {
	    nav_data.value.y = value ;
	    nav_data.dimMask = NavigDimensionY ;
	}

	nav_data.valueMask = NavValue ;
	_XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, True);
	
	/* CR 7095: Don't move focus unless we must. */

        /* Call XmProcessTraversal after having removed the
	 * traverseObscuredCallback, so that it isn't called and 
         * result in the paging operation going back to origin.
	 */
	tmp = sw->swindow.traverseObscuredCallback ;
	sw->swindow.traverseObscuredCallback = NULL ;
	if (XmIsTraversable(focus))
	  XmProcessTraversal(focus, XmTRAVERSE_CURRENT);
	else
	  XmProcessTraversal(sw->swindow.WorkWindow, XmTRAVERSE_CURRENT);
	sw->swindow.traverseObscuredCallback = tmp ;
    }
}



/************************************************************************
 *                                                                      *
 * LeftEdge - move the view to the left edge                            *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
LeftEdge(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;

    if (!sw->swindow.hScrollBar) return ;

    MoveWindow (sw, sw->swindow.hmin, 
		sw->swindow.hScrollBar->scrollBar.orientation);
}

/************************************************************************
 *                                                                      *
 * RightEdge - move the view to the Right edge                          *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
RightEdge(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;

    if (!sw->swindow.hScrollBar) return ;

    MoveWindow (sw, sw->swindow.hmax - sw->swindow.hExtent,
		sw->swindow.hScrollBar->scrollBar.orientation);
}


/************************************************************************
 *                                                                      *
 * TopEdge - move the view to the Top edge                              *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
TopEdge(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;

    if (!sw->swindow.vScrollBar) return ;

    MoveWindow (sw, sw->swindow.vmin, 
		sw->swindow.vScrollBar->scrollBar.orientation);
}


/************************************************************************
 *                                                                      *
 * BottomEdge - move the view to the Bottom edge                        *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
BottomEdge(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;

    if (!sw->swindow.vScrollBar) return ;

    MoveWindow (sw, sw->swindow.vmax - sw->swindow.vExtent,
		sw->swindow.vScrollBar->scrollBar.orientation);
}


/************************************************************************
 *                                                                      *
 * PageLeft - Scroll left a page                                        *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
PageLeft(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    int value ;
    
    if (sw->swindow.hScrollBar) 
	value = sw->swindow.hOrigin - 
	    (sw->swindow.hScrollBar)->scrollBar.page_increment;
    else
	value = sw->swindow.hOrigin - sw->swindow.WorkWindow->core.width;
            
    MoveWindow (sw, MAX(value, sw->swindow.hmin), XmHORIZONTAL);
}
/************************************************************************
 *                                                                      *
 * PageRight - Scroll Right a page                                      *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
PageRight(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    int value ;
    
    if (sw->swindow.hScrollBar) 
	value = sw->swindow.hOrigin + 
	    (sw->swindow.hScrollBar)->scrollBar.page_increment;
    else
	value = sw->swindow.hOrigin + sw->swindow.WorkWindow->core.width;
            
    MoveWindow (sw, MIN(value, (sw->swindow.hmax - sw->swindow.hExtent)),
		XmHORIZONTAL);
}


/************************************************************************
 *                                                                      *
 * PageUp - Scroll up a page                                            *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
PageUp(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    int value ;
    
    if (sw->swindow.vScrollBar) 
	value = sw->swindow.vOrigin - 
	    (sw->swindow.vScrollBar)->scrollBar.page_increment;
    else
	value = sw->swindow.vOrigin - sw->swindow.WorkWindow->core.height;
            
    MoveWindow (sw, MAX(value, sw->swindow.vmin), XmVERTICAL);
}


/************************************************************************
 *                                                                      *
 * PageDown - Scroll Down a page                                        *
 *                                                                      *
 ************************************************************************/
/* ARGSUSED */
static void 
PageDown(
        Widget wid,
        XEvent *event,
        String *params,
        Cardinal *num_params )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    int value ;
    
    if (sw->swindow.vScrollBar) 
	value = sw->swindow.vOrigin + 
	    (sw->swindow.vScrollBar)->scrollBar.page_increment;
    else
	value = sw->swindow.vOrigin + sw->swindow.WorkWindow->core.height;
            
    MoveWindow (sw, MIN(value, (sw->swindow.vmax - sw->swindow.vExtent)),
		XmVERTICAL);

}




/************************************************************************
 *									*
 *  ClassPartInitialize - Set up the fast subclassing.			*
 *									*
 ************************************************************************/
static void 
ClassPartInitialize(
        WidgetClass wc )
{
    XmScrolledWindowWidgetClass swc = (XmScrolledWindowWidgetClass) wc;
    XmScrolledWindowWidgetClass super =
	(XmScrolledWindowWidgetClass) wc->core_class.superclass;
    XmScrolledWindowClassExt         *wcePtr, *scePtr;


    /* Inheritance of the auto drag drop site rectangles */
   
    wcePtr = _XmGetScrolledWindowClassExtPtr(swc, NULLQUARK);

    if (((WidgetClass)swc != xmScrolledWindowWidgetClass) && (*wcePtr)) {

	scePtr = _XmGetScrolledWindowClassExtPtr(super, NULLQUARK);

	if ((*wcePtr)->get_hor_rects == XmInheritGetAutoDragRectsProc)
	    (*wcePtr)->get_hor_rects = (*scePtr)->get_hor_rects;

	if ((*wcePtr)->get_vert_rects == XmInheritGetAutoDragRectsProc)
	    (*wcePtr)->get_vert_rects = (*scePtr)->get_vert_rects;

    }


    _XmFastSubclassInit (wc, XmSCROLLED_WINDOW_BIT);

    /* Install the scrollFrame trait for all subclasses as well. */
    XmeTraitSet((XtPointer)wc, XmQTscrollFrame, (XtPointer)&scrolledWindowSFT);
}


/************************************************************************
 *									*
 *  Initialize								*
 *									*
 ************************************************************************/
/* ARGSUSED */
static void 
Initialize(
        Widget rw,
        Widget nw,
        ArgList args,
        Cardinal *num_args )
{
    XmScrolledWindowWidget request = (XmScrolledWindowWidget) rw ;
    XmScrolledWindowWidget new_w = (XmScrolledWindowWidget) nw ;
    Cardinal n;
    Arg loc_args[5] ;

    /****************
     *
     *  Check validity
     *
     ****************/

    if(!XmRepTypeValidValue( XmRID_SCROLLING_POLICY,
			    new_w->swindow.ScrollPolicy, (Widget) new_w)    )
    {
	new_w->swindow.ScrollPolicy = XmAPPLICATION_DEFINED;
    }

    /* VisualPolicy has already been set using ScrollPolicy in the
       default proc, check that no one changed it */
    if(!XmRepTypeValidValue( XmRID_VISUAL_POLICY,
			    new_w->swindow.VisualPolicy, (Widget) new_w)    )
    {
        if (new_w->swindow.ScrollPolicy == XmAUTOMATIC)
            new_w->swindow.VisualPolicy = XmCONSTANT;
        else
	    new_w->swindow.VisualPolicy = XmVARIABLE;
    }


    if ((new_w->swindow.ScrollPolicy == XmAPPLICATION_DEFINED) &&
        (new_w->swindow.VisualPolicy != XmVARIABLE))
    {
	XmeWarning( (Widget) new_w, SWMessage11);
        new_w->swindow.VisualPolicy = XmVARIABLE;        
    }

    /* force constant & automatic */
    if (new_w->swindow.ScrollPolicy == XmAUTOMATIC) 
    	new_w->swindow.VisualPolicy = XmCONSTANT;


    if (new_w->swindow.ScrollBarPolicy == (unsigned char)RESOURCE_DEFAULT)
    {
        if (new_w->swindow.ScrollPolicy == XmAUTOMATIC)
           new_w->swindow.ScrollBarPolicy = XmAS_NEEDED;
        else
           new_w->swindow.ScrollBarPolicy = XmSTATIC;
    }

    if(!XmRepTypeValidValue(XmRID_SCROLL_BAR_DISPLAY_POLICY,
			    new_w->swindow.ScrollBarPolicy, (Widget) new_w) )
    {
        if (new_w->swindow.ScrollPolicy == XmAUTOMATIC)
           new_w->swindow.ScrollBarPolicy = XmAS_NEEDED;
        else
           new_w->swindow.ScrollBarPolicy = XmSTATIC;
    }	


    if ((new_w->swindow.VisualPolicy == XmVARIABLE) &&
	(request->swindow.ScrollBarPolicy == XmAS_NEEDED))
    {
	XmeWarning( (Widget) new_w, SWMessage8);
	new_w->swindow.ScrollBarPolicy = XmSTATIC;
    }


    if(!XmRepTypeValidValue( XmRID_SCROLL_BAR_PLACEMENT,
			    new_w->swindow.Placement, (Widget) new_w)    )
    {
	new_w->swindow.Placement = XmBOTTOM_RIGHT;
    }	


    if (new_w->swindow.pad == (Dimension)RESOURCE_DEFAULT) 
        new_w->swindow.pad = DEFAULT_SPACING;
    

    if (request->manager.shadow_thickness == (Dimension)RESOURCE_DEFAULT)
        if (new_w->swindow.ScrollPolicy == XmAUTOMATIC)
            new_w->manager.shadow_thickness = 2;
	else
            new_w->manager.shadow_thickness = 0;
	

    /****************
     *
     * Init internal fields now
     *
     ****************/

    new_w->swindow.FromResize = FALSE;

    /* the mins actually never change, the others, max, extent, etc,
       get update the first time the SW is resized */
    new_w->swindow.hmin = 0 ;
    new_w->swindow.vmin = 0 ;
    
    /****************
     *
     * We will set the X and Y offsets to the pad values. That lets us use
     * the four variables as a "margin" to the user, but MainWindow can still
     * dink around with them if it wants.
     *
     ****************/
    new_w->swindow.XOffset = new_w->swindow.WidthPad;
    new_w->swindow.YOffset = new_w->swindow.HeightPad;

    /* these fields are used to find out if the object need
       to be reposition according to the scrollbars minima. */
    /* that happens the first time and
       when the scrollbars disappears too */
    new_w->swindow.sw_prev_x = MAXPOS;
    new_w->swindow.sw_prev_y = MAXPOS;


    /****************
     *
     * Add our class translation table
     *
     ****************/
    XtAugmentTranslations((Widget) new_w, (XtTranslations)
			  ((XmManagerClassRec *)XtClass(new_w))->
			               manager_class.translations);

    /***********************
      Initialize the auto_drag timer */

    new_w->swindow.auto_drag_timer = 0 ;
    
    /***********************
      Initialize the auto_drag rectangles */

    if (new_w->swindow.auto_drag_model == XmAUTO_DRAG_ENABLED)
      new_w->swindow.auto_drag_rects = XtCalloc(1, sizeof(AutoDragRectsRec));
    else
      new_w->swindow.auto_drag_rects = NULL;


    /***********************
      Initialize the scroll_frame flag */

    new_w->swindow.scroll_frame_inited = False;

    /****************
     *
     * APPLICATION_DEFINED : we're almost done.
     *
     ****************/
    if (new_w->swindow.ScrollPolicy == XmAPPLICATION_DEFINED) {
	Dimension future_width, future_height ; /* without kids */

	new_w->swindow.InInit = False;

	/* Need to default AreaWidth&Height to something that makes 
	   sense, since they might be used in Redisplay before layout
	   if no kid is present in the SW.
	   They will be changed if the SW gets a child.
	   If the SW doesn't get a child, its size will be DEFAULT_SIZE if
	   it hasn't one already (if it is null). */

	if (new_w->core.width == 0) future_width = DEFAULT_SIZE ;
	else future_width = new_w->core.width ;
	if (new_w->core.height == 0) future_height = DEFAULT_SIZE ;
	else future_height = new_w->core.height ;

	if (future_width > new_w->manager.shadow_thickness*2)
	    new_w->swindow.AreaWidth = future_width
		- (new_w->manager.shadow_thickness * 2);
	else
	    new_w->swindow.AreaWidth = 2 ;

	if (future_height > new_w->manager.shadow_thickness*2)
	    new_w->swindow.AreaHeight = future_height
		- (new_w->manager.shadow_thickness * 2);
	else
	    new_w->swindow.AreaHeight = 2 ;

	/* In app defined, we do not initialize the scrollframe,
	   so that List and Text could check that it
	   hasn't been done yet and do it */

	return;	
    }


    /***************--------------------------***********************
     *
     * Else we're in AUTOMATIC, and we are about to create private
     *  children, so set up a flag for use in InsertChild
     *
     *****************/

    new_w->swindow.InInit = True;

    /* Default dimension here, not in ChangeManaged because
       auto mode isn't based on children size */
    if (new_w->core.width == 0) new_w->core.width = DEFAULT_SIZE ;
    if (new_w->core.height == 0) new_w->core.height = DEFAULT_SIZE ;

    /* default Area fields too, see above comments */
    if (new_w->core.width > new_w->manager.shadow_thickness*2)
	new_w->swindow.AreaWidth = new_w->core.width 
	    - (new_w->manager.shadow_thickness * 2);
    else
	new_w->swindow.AreaWidth = 2 ;

    if (new_w->core.height > new_w->manager.shadow_thickness*2)
	new_w->swindow.AreaHeight = new_w->core.height 
	    - (new_w->manager.shadow_thickness * 2);
    else
	new_w->swindow.AreaHeight = 2 ;
 
	
    /****************
     *
     * create a clip window.
     *
     ****************/
    
    n = 0 ;
    XtSetArg (loc_args[n], XmNscrolledWindowChildType, XmCLIP_WINDOW); n++ ;
    /* give an initial size to the clipwindow, since when layoutDirection
       is reversed, the clipwindow size is used from ConstraintInitialize
       (before the first layout, which resizes the clipwindow) */
    XtSetArg (loc_args[n], XmNwidth, new_w->swindow.AreaWidth); n++ ;
    XtSetArg (loc_args[n], XmNheight, new_w->swindow.AreaHeight); n++ ;
    new_w->swindow.ClipWindow = (XmDrawingAreaWidget)
	XtCreateManagedWidget("ClipWindow", xmClipWindowWidgetClass,
			      (Widget) new_w, loc_args, n);

    /***********************
      Initialize the scrollFrame with move callback for Automatic */

    ((XmScrollFrameTrait) 
     XmeTraitGet((XtPointer) XtClass(nw), XmQTscrollFrame))->
	init(nw, SliderMove, (Widget) new_w->swindow.ClipWindow);

    /****************
     *
     *  create the scroll bars.
     *  location and size don't matter right now - 
     *  we'll figure them out for real at changemanaged time.
     *
     *  The trait AddNavigator method will be set up in 
     *  InsertChild so that APP_DEFINED (ScrolledList, Text, etc)
     *  get it for their scrollbars as well.
     *
     ****************/



    /**********************
     * vertical scrollbar */

    n = 0 ;
    XtSetArg (loc_args[n], XmNorientation, XmVERTICAL); n++;
    new_w->swindow.vScrollBar = (XmScrollBarWidget) 
	XtCreateManagedWidget("VertScrollBar", xmScrollBarWidgetClass,
			      (Widget) new_w, loc_args, n); 

    /************************
     * horizontal scrollbar */

    n = 0 ;
    XtSetArg (loc_args[n], XmNorientation, XmHORIZONTAL); n++;
    new_w->swindow.hScrollBar = (XmScrollBarWidget) 
	XtCreateManagedWidget("HorScrollBar", xmScrollBarWidgetClass,
			      (Widget) new_w, loc_args, n);

    /* could set childType for the scrollbar here too, but it's more 
       convenient to do that in InsertChild, since app defined scrollbar
       are only available down there */


    /* turn off the InsertChild flag */
    new_w->swindow.InInit = FALSE;    
}



/************************************************************************
 *									*
 *  Redisplay - General redisplay function called on exposure events.	*
 *									*
 ************************************************************************/
static void 
Redisplay(
        Widget wid,
        XEvent *event,
        Region region )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    Dimension st, bw;
    
    if (!XtIsRealized (wid)) return ; /* get rid of that when GM redone*/
    
    st = sw->manager.shadow_thickness;
    if (sw->swindow.ScrollPolicy == XmAUTOMATIC) {
	XmeDrawShadows (XtDisplay (sw), XtWindow (sw), 
 			 sw -> manager.bottom_shadow_GC,
 			 sw -> manager.top_shadow_GC,
 			 sw->swindow.ClipWindow->core.x - st, 
 			 sw->swindow.ClipWindow->core.y - st, 
 			 sw -> swindow.AreaWidth + (st * 2),
 			 sw -> swindow.AreaHeight + (st * 2), 
			 sw->manager.shadow_thickness,
 			 XmSHADOW_OUT);
    } else {
	if (sw->swindow.WorkWindow) {
	    bw = sw->swindow.WorkWindow->core.border_width;
	    XmeDrawShadows (XtDisplay (sw), XtWindow (sw), 
			   sw -> manager.bottom_shadow_GC,
			   sw -> manager.top_shadow_GC,
			   sw->swindow.WorkWindow->core.x - st,
			   sw->swindow.WorkWindow->core.y - st,
			   sw -> swindow.AreaWidth + ((bw + st) * 2),
			   sw -> swindow.AreaHeight + ((bw + st) * 2), 
			   sw->manager.shadow_thickness,
			   XmSHADOW_OUT);
	}
	else
	    XmeDrawShadows (XtDisplay (sw), XtWindow (sw), 
			   sw -> manager.bottom_shadow_GC,
			   sw -> manager.top_shadow_GC,
			   0, 0,
			   sw -> swindow.AreaWidth + (st * 2),
			   sw -> swindow.AreaHeight + (st * 2), 
			   sw->manager.shadow_thickness,
			   XmSHADOW_OUT);
   }

    XmeRedisplayGadgets(wid, event, region);
   
}


/************************************************************************
 *									*
 *  InsertChild: set internal pointers					*
 *									*
 ************************************************************************/
static void 
InsertChild(
        Widget w )
{

    XmManagerWidgetClass superclass = 
	            (XmManagerWidgetClass) xmManagerWidgetClass;
    XmScrolledWindowWidget   sw = (XmScrolledWindowWidget)w->core.parent ;
    XmScrolledWindowConstraint swc = GetSWConstraint(w);
    Arg args[5] ;
    Cardinal n ;
    XtWidgetProc insert_child;
	    
    if (!XtIsRectObj(w)) return;
  
    _XmProcessLock();
    insert_child = superclass->composite_class.insert_child;
    _XmProcessUnlock();

    /****************
     * Manage the child type defaulting first -
     * for auto created children (clip/scrollbars/sep) as well
     *
     ****************/
    if (swc->child_type == (unsigned char) RESOURCE_DEFAULT) {

	if (XmIsScrollBar(w)) {
	    if (((XmScrollBarWidget) w)->scrollBar.orientation 
		== XmHORIZONTAL) {
		swc->child_type = XmHOR_SCROLLBAR ;
	    } else {
		swc->child_type = XmVERT_SCROLLBAR ;
	    }
	} else {
	    swc->child_type = XmWORK_AREA ;
	}
    }
						      
    if ((swc->child_type == XmHOR_SCROLLBAR) ||
	(swc->child_type == XmVERT_SCROLLBAR)) {
	/************************/
	/* Deal with the Scrollbar auto drag drop site register here, */
	/* create the dropsite only if resource says so */
	/* The model is: the scrollbars are used as drop site,
	   with 2 rectangles around the workarea, defined
	   upon resize using XmDropSiteUpdate in UpdateAutoDrag */

	/* this is done for both AUTO and APP_DEFINED scrollbars */

	if (sw->swindow.auto_drag_model == XmAUTO_DRAG_ENABLED) {
	    n = 0 ;
	    XtSetArg(args[n], XmNdropProc, HandleDrop); n++ ;
	    XtSetArg(args[n], XmNdragProc, HandleDrag); n++ ;
	    XtSetArg(args[n], XmNnumImportTargets, 1); n++ ;
	    XtSetArg(args[n], XmNimportTargets, w); n++ ;
	    XmDropSiteRegister(w, args, n);
	}
    }

	    
							  
    /************************
      Do the navigator association now. 
      ************************/
    if (swc->child_type == XmHOR_SCROLLBAR)
	((XmScrollFrameTrait) 
	 XmeTraitGet((XtPointer) XtClass((Widget)(sw)), XmQTscrollFrame))->
	     addNavigator((Widget)sw, w, NavigDimensionX);
    else 
    if (swc->child_type == XmVERT_SCROLLBAR)
	((XmScrollFrameTrait) 
	 XmeTraitGet((XtPointer) XtClass((Widget)(sw)), XmQTscrollFrame))->
	     addNavigator((Widget)sw, w, NavigDimensionY);
		



    /************************
      Check if auto created child (Clipwindow, Scrollbars) 
       if yes, insert using superclass method */
    if (sw->swindow.InInit) {
	(*insert_child)(w);
    } else {
    

	/****************
	 *
	 * APP_DEFINED, handle scrollbars case, set the workwindow if not
	 *         already set.
	 *
	 ****************/
 
	if (sw->swindow.ScrollPolicy == XmAPPLICATION_DEFINED) {
	    
	    if (swc->child_type == XmHOR_SCROLLBAR)
		sw->swindow.hScrollBar = (XmScrollBarWidget) w;
	    else
	    if (swc->child_type == XmVERT_SCROLLBAR)
		sw->swindow.vScrollBar = (XmScrollBarWidget) w;
	    else 
            if (swc->child_type == XmWORK_AREA) {
		if (!sw->swindow.WorkWindow) sw->swindow.WorkWindow = w;
	    }
	}
	

	/****************
	 *
	 *  AUTOMATIC: set the workwindow and reparent it to the clipwindow .
	 *
	 ****************/
	else {
	    /* maintain the old workwindow semantics */
	    if (swc->child_type == XmWORK_AREA) sw->swindow.WorkWindow = w;

	    /* reparent all the clipped type children */
	    if ((swc->child_type == XmWORK_AREA) ||
		(swc->child_type == XmSCROLL_HOR) ||
		(swc->child_type == XmSCROLL_VERT) ||
		(swc->child_type == XmNO_SCROLL)) {
		w->core.parent = (Widget )sw->swindow.ClipWindow;
	    }
	}
	
	/* call insert child now. For the reparented workarea, that will
	   insert it in the clipwindow child list */
	
	(*insert_child)(w);
	
	/* Widgets already there might still be hanging around,
	   it is the responsability of the application to destroy
	   or unmanage or unmap them */
    }

}

/************************************************************************
 *									*
 *  DeleteChild: reset internal pointers to NULL			*
 *									*
 ************************************************************************/
static void 
DeleteChild(
        Widget child )
{
    Widget swWid = XtParent(child);
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) swWid;
    XtWidgetProc      delete_child;
    
    if (child == sw->swindow.WorkWindow)
        sw->swindow.WorkWindow = NULL;
    /* auto drag will stop by itself when destroying these */
    if (child == (Widget) sw->swindow.hScrollBar)
        sw->swindow.hScrollBar = NULL;
    if (child == (Widget) sw->swindow.vScrollBar)
        sw->swindow.vScrollBar = NULL;

    /* Clean up the Navigator.  Metro Link fix, suggested by
     * Kevin B. Hendricks of Java-Linux project. */
    RemoveNavigator(swWid, child);

    _XmProcessLock();
    delete_child = 
	((CompositeWidgetClass)xmScrolledWindowClassRec.core_class.superclass)
			->composite_class.delete_child;
    _XmProcessUnlock();
    (*delete_child)(child);
}

 
/************************************************************************
 *									*
 * ComputeLocations - position the scrollbars and the workarea		*
 *       using the scrollbar placement resource				*
 *	Used in both Variable and Constant layout			*
 *									*
 ************************************************************************/
static void 
ComputeLocations(
        XmScrolledWindowWidget sw,
	Dimension HSBht, Dimension VSBht,
        Boolean HasHSB, Boolean HasVSB,
	Position * newx, Position * newy,
	Position * hsbX, Position * hsbY,
 	Position * vsbX, Position * vsbY)
{
    Dimension shad = sw->manager.shadow_thickness, 
              pad = sw->swindow.pad,
              vsb_width, hsb_height;
    
    vsb_width = (HasVSB) ? (sw->swindow.vScrollBar->core.width) : 0;

    hsb_height = (HasHSB) ? (sw->swindow.hScrollBar->core.height) : 0;


/****************
 *
 * Initialize the placement variables - these are correct for
 * bottom-right placement of the scrollbars.
 *
 ****************/
    *newx = sw->swindow.XOffset + shad + HSBht;
    *newy = sw->swindow.YOffset + shad + VSBht;
    *hsbX = sw->swindow.XOffset;
    *vsbY = sw->swindow.YOffset;
    *vsbX = (HasVSB) ? (sw->core.width -  sw->swindow.WidthPad -
			vsb_width) : sw->core.width;
    *hsbY = (HasHSB) ? (sw->core.height - sw->swindow.HeightPad - 
			hsb_height): sw->core.height;
/****************
 *
 * Check out the scrollbar placement policy and hack the locations
 * accordingly.
 *
 ****************/
    switch (sw->swindow.Placement)
    {
	case XmTOP_LEFT:
                *newx = (HasVSB) ? (vsb_width +
    		                   sw->swindow.XOffset + pad + shad +
				   HSBht) 
				: (sw->swindow.XOffset + shad + HSBht);

                *newy = (HasHSB) ? (hsb_height +
    		                   sw->swindow.YOffset + pad + shad +
				   VSBht) 
				: (sw->swindow.YOffset + shad + VSBht);

		*hsbX = *newx - HSBht - shad;
		*hsbY = sw->swindow.YOffset;
		*vsbX = sw->swindow.XOffset;
		*vsbY = *newy - VSBht - shad;
		break;
	case XmTOP_RIGHT:
                *newy = (HasHSB) ? (hsb_height +
    		                   sw->swindow.YOffset + pad + shad +
				   VSBht) 
				: (sw->swindow.YOffset + shad + VSBht);

		*vsbY = *newy - shad - VSBht;
		*hsbY = sw->swindow.YOffset;
		break;
	case XmBOTTOM_LEFT:
                *newx = (HasVSB) ? (vsb_width +
    		                   sw->swindow.XOffset + pad + shad +
				   HSBht) 
				: (sw->swindow.XOffset + shad + HSBht);
		*hsbX = *newx - HSBht - shad;
		*vsbX = sw->swindow.XOffset;
		break;
	default:
		break;
    }
}


static void 
CheckKids(
        XmScrolledWindowWidget sw )
{

    /* do a sanity check */
    if( sw->swindow.WorkWindow != NULL &&
       sw->swindow.WorkWindow->core.being_destroyed ) {
	sw->swindow.WorkWindow = NULL;
    }
    if( sw->swindow.hScrollBar != NULL &&
       sw->swindow.hScrollBar->core.being_destroyed ) {
	sw->swindow.hScrollBar = NULL;
    }
    if( sw->swindow.vScrollBar != NULL &&
       sw->swindow.vScrollBar->core.being_destroyed ) {
	sw->swindow.vScrollBar = NULL;
    }
}



/************************************************************************
 *									*
 * VariableLayout - Layout the workarea and the scrollbars for    	*
 *      APPLICATION_DEFINED. ScrolledWindow has a size already.    	*
 *   APP_DEFINED SW still use sw->swindow.WorkWindow			*
 ************************************************************************/
static void 
VariableLayout(
        XmScrolledWindowWidget sw )
{
    Position	 newx, newy, vsbX, vsbY, hsbX, hsbY;
    Dimension HSBht = 0, VSBht = 0, VSBwidth = 0, HSBheight = 0;
    Dimension MyWidth, MyHeight, childWidth, childHeight;
    Dimension shad = sw->manager.shadow_thickness, 
              pad = sw->swindow.pad, bw;
    int	tmp;
    Boolean HasHSB, HasVSB, HSBTrav = True, VSBTrav = True;
    XtWidgetGeometry  desired, preferred;


    CheckKids(sw);

    /* no Workwindow, make scrollbars invisible --
       Doesn't seem right to do that given app_defined policy... */
    if (!ExistManaged(sw->swindow.WorkWindow))	
    {					
	if (sw->swindow.vScrollBar)
	    XmeConfigureObject((Widget) sw->swindow.vScrollBar,
			       sw->core.width, 0,
			       (sw->swindow.vScrollBar)->core.width,
			       (sw->swindow.vScrollBar)->core.height,
			       (sw->swindow.vScrollBar)->core.border_width);

	if (sw->swindow.hScrollBar)
	    XmeConfigureObject((Widget) sw->swindow.hScrollBar,
			       0, sw->core.height,
			       (sw->swindow.hScrollBar)->core.width,
			       (sw->swindow.hScrollBar)->core.height,
			       (sw->swindow.hScrollBar)->core.border_width);
	return;
    }


    bw = sw->swindow.WorkWindow->core.border_width ;
              
    /* Compute the available size after a subclass, like mainwindow,
       has taken its share of layout. */

    /* worry about going negative */
    tmp = (int) sw->core.width - sw->swindow.XOffset - sw->swindow.WidthPad;
    if (tmp <= 0)
        MyWidth = 10;
    else 
        MyWidth = (Dimension )tmp;
    tmp = (int) sw->core.height - sw->swindow.YOffset - sw->swindow.HeightPad;
    if (tmp <= 0)
        MyHeight = 10;
    else 
        MyHeight = (Dimension )tmp;

    
/* CR 5319 begin */
    if (sw->core.width > sw->swindow.WidthPad + shad*2)
      sw->swindow.AreaWidth = sw->core.width - sw->swindow.WidthPad
	- ((shad * 2) );
    else
      sw->swindow.AreaWidth = 0;
    if (sw->core.height > sw->swindow.HeightPad + shad*2)
      sw->swindow.AreaHeight = sw->core.height - sw->swindow.HeightPad
	- ((shad * 2) );
    else
      sw->swindow.AreaHeight = 0;
/* CR 5319 end */


    tmp = (int) MyWidth - (((int )shad+(int )bw) * 2);
    if (tmp <= 0)
        childWidth = 2;
    else 
        childWidth = (Dimension )tmp;

    tmp = (int )MyHeight - (((int )shad+(int )bw) * 2);
    if (tmp <= 0)
        childHeight = 2;
    else 
        childHeight = (Dimension )tmp;

/****************
 *
 * OK, we just figured out the maximum size for the child (with no
 * scrollbars (it's in childWidth, childHeight). Now query the 
 * kid geometry - tell him that we are going to resize him to childWidth,
 * childHeight and give him a chance to muck with the scrollbars or whatever.
 * Then, we re-layout according to the current scrollbar config.
 *
 ****************/
    
    desired.x = shad + sw->swindow.XOffset;
    desired.y = shad + sw->swindow.YOffset;
    desired.border_width = bw;
    desired.height = childHeight;
    desired.width = childWidth;
    desired.request_mode = (CWWidth | CWHeight);

    /* child may manage or unmanage the scrollbars, set a flag up
       and check for it in ChangeManaged */
    sw->swindow.FromResize = TRUE;

    XtQueryGeometry(sw->swindow.WorkWindow, &desired, &preferred);

    sw->swindow.FromResize = FALSE;
	    
    bw = preferred.border_width;

    HasHSB = ExistManaged((Widget) sw->swindow.hScrollBar);
    HasVSB = ExistManaged((Widget) sw->swindow.vScrollBar);

    if (HasHSB) {
	HSBht = sw->swindow.hScrollBar->primitive.highlight_thickness ;
	HSBTrav = sw->swindow.hScrollBar->primitive.traversal_on ; 
	HSBheight = sw->swindow.hScrollBar->core.height ;
    }

    if (HasVSB) {
	VSBht = sw->swindow.vScrollBar->primitive.highlight_thickness ;
	VSBTrav = sw->swindow.vScrollBar->primitive.traversal_on ; 
	VSBwidth = sw->swindow.vScrollBar->core.width ; 
    }

/****************
 *
 * Here's a cool undocumented feature. If the scrollbar is not
 * traversable,but has a highlight thickness, we assume it's something
 * that wants to draw the highlight around the workwindow, and wants to
 * have the scrollbars line up properly. Something like Scrolled Text,
 * for instance :-)
 *
 ****************/
    if (ExistManaged(sw->swindow.WorkWindow) &&
        XmIsPrimitive(sw->swindow.WorkWindow))
    {
        if (HSBht && !HSBTrav) HSBht = 0;
        if (VSBht && !VSBTrav) VSBht = 0;
    }


/****************
 *
 * Get the position for scrollbars and workarea
 *
 ****************/
    ComputeLocations(sw, 
		     HSBht, VSBht, HasHSB, HasVSB, 
		     &newx, &newy, &hsbX, &hsbY, &vsbX, &vsbY); 

/* reset the child sizes */

    childWidth = (HasVSB) ? MyWidth - (VSBwidth + 
            (2 * VSBht) + SB_BORDER_WIDTH + ((HSBht + bw + shad)*2) + pad )
		       : MyWidth - ((HSBht + shad+bw) * 2);

    childHeight = (HasHSB) ? MyHeight - (HSBheight +
            (2 * HSBht) + SB_BORDER_WIDTH + ((VSBht + shad + bw)*2) + pad ) 
			: MyHeight - ((VSBht + shad+bw) * 2);

    if (childWidth > MyWidth) childWidth = 2;
    if (childHeight > MyHeight) childHeight = 2;

    XmeConfigureObject(sw->swindow.WorkWindow, newx, newy, 
		       childWidth, childHeight, bw);

    /* not needed here, because never auto, but we leave it for now */
    if (sw->swindow.ClipWindow)
	XmeConfigureObject((Widget) sw->swindow.ClipWindow, newx,
			   newy, childWidth, childHeight, 0);

    
    sw->swindow.AreaWidth = childWidth;
    sw->swindow.AreaHeight = childHeight;

    /* always forces one scrollbar dimension */
    sw->swindow.hsbWidth = childWidth  + ((HSBht + shad + bw) * 2);
    sw->swindow.vsbHeight = childHeight  + ((VSBht + shad + bw) * 2);

     if (HasVSB)
	 XmeConfigureObject((Widget) sw->swindow.vScrollBar, vsbX, vsbY,
			    VSBwidth, sw->swindow.vsbHeight, 
			    SB_BORDER_WIDTH);

     if (HasHSB)
	 XmeConfigureObject((Widget) sw->swindow.hScrollBar, hsbX, hsbY,
			    sw->swindow.hsbWidth, HSBheight, 
			    SB_BORDER_WIDTH);

}


/************************************************************************
 *									*
 * ConstantLayout - Layout the scrolled window for AUTOMATIC		*
 *									*
 ************************************************************************/
static void 
ConstantLayout(
        XmScrolledWindowWidget sw )
{
    XmDrawingAreaWidget clip = (XmDrawingAreaWidget) sw->swindow.ClipWindow ;
    int i, hinc, hpage_inc, vinc, vpage_inc;
    Position newx, newy;
    Position hsbX, hsbY, vsbX, vsbY, clipX, clipY;
    int clipWidth, clipHeight;
    int MyWidth, MyHeight;
    Dimension  HSBht, VSBht, 
               shad = sw->manager.shadow_thickness, 
               pad = sw->swindow.pad;
    Boolean HasHSB, HasVSB, HSBExists, VSBExists, no_scroll_present = False;
    XmScrolledWindowConstraint swc;
    Widget child ;
    XmNavigatorDataRec nav_data ;

    /* Compute the available size after a subclass, like mainwindow,
       has taken its share of layout. */

    MyWidth = sw->core.width - sw->swindow.XOffset  - sw->swindow.WidthPad;
    MyHeight = sw->core.height - sw->swindow.YOffset  - sw->swindow.HeightPad;


    HSBExists = ExistManaged((Widget) sw->swindow.hScrollBar);
    VSBExists = ExistManaged((Widget) sw->swindow.vScrollBar);


    /* If there's no kid to clip, keep the scrollbars invisible
       by moving them out of the frame */

    for (i = 0; i < clip->composite.num_children; i++) {
	if (XtIsManaged(clip->composite.children[i])) break ;
    }
	
    /* ran thru the entire list: no managed child in the clipwindow */
    if (i == clip->composite.num_children) {				
        if (VSBExists) {
            XmeConfigureObject((Widget) sw->swindow.vScrollBar,
			       sw->core.width,
			       sw->swindow.vScrollBar->core.y,
			       (sw->swindow.vScrollBar)->core.width,
			       (sw->swindow.vScrollBar)->core.height,
			       (sw->swindow.vScrollBar)->core.border_width);
	    sw->swindow.vsbX = sw->swindow.vScrollBar->core.x;
        }
        if (HSBExists) {
	    XmeConfigureObject((Widget) sw->swindow.hScrollBar,
			       sw->swindow.hScrollBar->core.x,
			       sw->core.height,
			       (sw->swindow.hScrollBar)->core.width,
			       (sw->swindow.hScrollBar)->core.height,
			       (sw->swindow.hScrollBar)->core.border_width);
	    sw->swindow.hsbY = sw->swindow.hScrollBar->core.y;
        }

	/* looks bogus, but who care of this extreme case */
	sw->swindow.AreaWidth = sw->core.width  - 
	    sw->swindow.WidthPad - ((shad * 2) );
	sw->swindow.AreaHeight = sw->core.height - 
	    sw->swindow.HeightPad - ((shad * 2) );

        XmeConfigureObject((Widget) clip, 
			   shad + sw->swindow.XOffset, 
			   shad + sw->swindow.YOffset,
			   sw->swindow.AreaWidth, sw->swindow.AreaHeight, 0);
	return;
    }



    HSBht = (HSBExists) ? 
	sw->swindow.hScrollBar->primitive.highlight_thickness : 0;
    VSBht = (VSBExists) ?
	sw->swindow.vScrollBar->primitive.highlight_thickness : 0;



    /* find the new min x and y children orig position and the
       new max width and height (position+dimension) stuff as well */

    newx = MAXPOS;
    newy = MAXPOS;
    sw->swindow.hmax = 0;
    sw->swindow.vmax = 0;

    for (i = 0; i < clip->composite.num_children; i++) {
	child = clip->composite.children[i];
	if (ExistManaged(child)) {
	    swc = GetSWConstraint(child);

	    /* only regular work_area and scroll_vert kids 
	       count for the vmax calculation */
	    if ((swc->child_type == XmWORK_AREA) ||
		(swc->child_type == XmSCROLL_VERT)) {
		newy = MIN(newy, swc->orig_y);
		sw->swindow.vmax = MAX(sw->swindow.vmax, 
				       swc->orig_y + child->core.height 
				       + 2*child->core.border_width);
	    } 	

	    /* only regular work_area and scroll_hor kids 
	       count for the hmax calculation */
	    if ((swc->child_type == XmWORK_AREA) ||
		(swc->child_type == XmSCROLL_HOR)) {
		newx = MIN(newx, swc->orig_x);
		sw->swindow.hmax = MAX(sw->swindow.hmax, 
				       swc->orig_x + child->core.width
				       + 2*child->core.border_width);
	    } 	
	    
	    if (swc->child_type == XmNO_SCROLL)
		no_scroll_present = True ;
	}
    }

    /* here we have to have an additional check for the case
       there is no WORKAREA but only HOR or VERT SCROLL. 
       We want to get a h/vmax not null in this case. */

    if (sw->swindow.hmax && !sw->swindow.vmax) {
	sw->swindow.vmax = MyHeight - (shad*2) ;
	newy = 0 ;
    }

    if (!sw->swindow.hmax && sw->swindow.vmax) {
	sw->swindow.hmax = MyWidth - (shad*2) ;
	newx = 0 ;
    }

    if (!sw->swindow.hmax && !sw->swindow.vmax) {
	/* check if there is only a NO_SCROLL... */
	if (no_scroll_present) {
	    sw->swindow.vmax = MyHeight - (shad*2) ;
	    sw->swindow.hmax = MyWidth - (shad*2) ;
	    newx = 0 ;
	    newy = 0 ;
	} else {
	    return ;
	}
    }

/****************
 *
 * Look at my size and set the clip dimensions accordingly. If the kid 
 * fits easily into the space, and we can ditch the scrollbars, set
 * the clip dimension to the size of the window and flag the scrollbars
 * as false. If the kid won't fit in either direction, or if the 
 * scrollbars are constantly in the way, set the clip dimensions to the
 * minimum area and flag both scrollbars as true. Otherwise, look at 
 * the dimensions, and see if either one needs a scrollbar.
 *
 ****************/

    if (((MyHeight - (shad*2)) >= sw->swindow.vmax) &&
	((MyWidth - (shad*2)) >= sw->swindow.hmax) &&
  	 (sw->swindow.ScrollBarPolicy == XmAS_NEEDED)) 
	{
	clipWidth = MyWidth - (shad * 2);		
	clipHeight = MyHeight - (shad * 2);
	HasVSB = HasHSB = FALSE;
	/* no visible scrollbar anymore, move the objects to their
	   origin */
	sw->swindow.sw_prev_x = MAXPOS ;
	sw->swindow.sw_prev_y = MAXPOS ;
    }
    else {
	clipHeight = (HSBExists) ?  
	    MyHeight - (sw->swindow.hScrollBar->core.height + 
			SB_BORDER_WIDTH + ((HSBht + shad) * 2 + pad))
		: MyHeight - ((VSBht + shad) * 2 );
	clipWidth = (VSBExists) ? 
	    MyWidth - (sw->swindow.vScrollBar->core.width + 
		       SB_BORDER_WIDTH + ((VSBht + shad) * 2 + pad))
		: MyWidth - ((HSBht + shad) * 2 );

        if ((((MyHeight - (shad*2)) < sw->swindow.vmax) &&
	     ((MyWidth - (shad*2)) < sw->swindow.hmax))  ||
     	    (sw->swindow.ScrollBarPolicy == XmSTATIC)) 
	    {	
		HasVSB = HasHSB = TRUE;
	    }
	else
	    {
		HasVSB = HasHSB = TRUE;
		if ((sw->swindow.vmax <= clipHeight) ||
		    (!VSBExists))
		    {
			clipWidth = MyWidth - ((HSBht + shad) * 2);
			clipHeight += VSBht;
			sw->swindow.sw_prev_y = MAXPOS ;
			HasVSB = FALSE;
		    }
		if ((sw->swindow.hmax <= clipWidth) ||
		    (!HSBExists))
		    {
			clipHeight = MyHeight - ((VSBht + shad) * 2);
			clipWidth += HSBht;
			sw->swindow.sw_prev_x = MAXPOS ;
			HasHSB = FALSE;
		    }
	    }
    }

    HasVSB = (HasVSB && VSBExists);
    HasHSB = (HasHSB && HSBExists);

    /* safe check */
    if (clipHeight < 2) clipHeight = 2 ;
    if (clipWidth < 2) clipWidth = 2 ;


/****************
 *
 * Now set characteristics for every navigators.
 *  we update the navigators even unmanaged, so that an application can
 *  unamanaged them and still use them as "movers".
 * If the new minimum position has changed (in either x or y direction)
 * we set the value to 0. otherwise, it stays what it was.
 *
 ****************/
    nav_data.valueMask = NavValue;
	
    /* slider size = extent */
    if ((sw->swindow.vmax - sw->swindow.vmin) < clipHeight)
	sw->swindow.vExtent = sw->swindow.vmax - sw->swindow.vmin;
    else
        sw->swindow.vExtent = clipHeight;

    /* always true the first time */
    if (newy != sw->swindow.sw_prev_y) {
	/* move all the navigators to 0,
	   which doesn't mean move the scrolled object to 0,
	   since they can have offset now */
	sw->swindow.vOrigin = 0;
	nav_data.value.y = sw->swindow.vOrigin ;
	nav_data.dimMask = NavigDimensionY ;
	_XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, True);
	sw->swindow.sw_prev_y = newy ;
    }

    if (sw->swindow.vOrigin > (sw->swindow.vmax - sw->swindow.vExtent)) {
    	sw->swindow.vOrigin = sw->swindow.vmax - sw->swindow.vExtent;
	nav_data.value.y = sw->swindow.vOrigin ;
	nav_data.dimMask = NavigDimensionY;
	_XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, True);
    }

    if ((vinc = (sw->swindow.vmax / 10)) < 1) vinc = 1;
    if ((vpage_inc = (clipHeight - (clipHeight / 10))) < 1) 
	vpage_inc = clipHeight;

    
    if ((sw->swindow.hmax - sw->swindow.hmin) < clipWidth)
        sw->swindow.hExtent = sw->swindow.hmax - sw->swindow.hmin;
    else
	sw->swindow.hExtent = clipWidth;

    if (newx != sw->swindow.sw_prev_x) {
	sw->swindow.hOrigin = 0;
	nav_data.value.x = sw->swindow.hOrigin ;
	nav_data.dimMask = NavigDimensionX ;
	_XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, True);
	/* when reversed, the moving proc has to be called manually,
	   for the reverse configure to happen. I might not get called
	   by the navigator API when the value already matches */
	if (LayoutIsRtoLM((Widget)sw)) 
	    SliderMove((Widget)sw->swindow.hScrollBar, clip, NULL);
	sw->swindow.sw_prev_x = newx ;
    }

    if (sw->swindow.hOrigin > (sw->swindow.hmax - sw->swindow.hExtent)) {
    	sw->swindow.hOrigin = sw->swindow.hmax - sw->swindow.hExtent;
	nav_data.value.x = sw->swindow.hOrigin ;
	nav_data.dimMask = NavigDimensionX ;
	_XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, True);
   }

    
    if ((hinc = (sw->swindow.hmax / 10)) < 1) hinc = 1;
    if ((hpage_inc = (clipWidth - (clipWidth / 10))) < 1) 
	hpage_inc = clipWidth;
	
    nav_data.value.x = sw->swindow.hOrigin ;
    nav_data.value.y = sw->swindow.vOrigin ;
    nav_data.minimum.x = sw->swindow.hmin ;
    nav_data.minimum.y = sw->swindow.vmin ;
    nav_data.maximum.x = sw->swindow.hmax ;
    nav_data.maximum.y = sw->swindow.vmax ;
    nav_data.slider_size.x = sw->swindow.hExtent ;
    nav_data.slider_size.y = sw->swindow.vExtent ;
    nav_data.increment.x = hinc ;
    nav_data.increment.y = vinc ;
    nav_data.page_increment.x = hpage_inc ;
    nav_data.page_increment.y = vpage_inc ;

    nav_data.dimMask = NavigDimensionX|NavigDimensionY ;
    nav_data.valueMask = NavValue|NavMinimum|NavMaximum|
	NavSliderSize|NavIncrement|NavPageIncrement;

    _XmSFUpdateNavigatorsValue((Widget)sw, &nav_data, False);
   


/****************
 *
 * Now the layout.
 *
 ****************/
   
    if (HasHSB)
        if (!HasVSB) 
	    sw->swindow.hsbWidth = MyWidth;
	else
	    sw->swindow.hsbWidth = clipWidth  + ((HSBht + shad) * 2);
    else
	sw->swindow.hsbWidth = MyWidth;

    if (HasVSB)
        if (!HasHSB) 
	    sw->swindow.vsbHeight = MyHeight;
	else 
	    sw->swindow.vsbHeight = clipHeight  + ((VSBht + shad) * 2);	
    else
	sw->swindow.vsbHeight = MyHeight;

    HSBht = (HasHSB) 
                 ? sw->swindow.hScrollBar->primitive.highlight_thickness : 0;
		 
    VSBht = (HasVSB) 
         	 ? sw->swindow.vScrollBar->primitive.highlight_thickness : 0;


/****************
 *
 * Get the position for scrollbars and workarea
 *
 ****************/
    ComputeLocations(sw, 
		     HSBht, VSBht, HasHSB, HasVSB, 
		     &clipX, &clipY, &hsbX, &hsbY, &vsbX, &vsbY); 

    
/****************
 *
 * Finally - move the widgets.
 *
 ****************/
    XmeConfigureObject((Widget) sw->swindow.ClipWindow, 
		       clipX, clipY, clipWidth, clipHeight, 0);
    sw->swindow.AreaWidth = clipWidth;
    sw->swindow.AreaHeight = clipHeight;

    if (HasVSB)
        XmeConfigureObject( (Widget) sw->swindow.vScrollBar, vsbX, vsbY,
		     sw->swindow.vScrollBar->core.width, sw->swindow.vsbHeight,
		     SB_BORDER_WIDTH);
    else
        if (VSBExists)
        {
            XmeConfigureObject((Widget) sw->swindow.vScrollBar, sw->core.width,
                       sw->swindow.YOffset, sw->swindow.vScrollBar->core.width,
                                       sw->swindow.vsbHeight, SB_BORDER_WIDTH);
            if (_XmFocusIsHere( (Widget) sw->swindow.vScrollBar))
                XmProcessTraversal( (Widget) sw, XmTRAVERSE_NEXT_TAB_GROUP);
        }

    if (HasHSB)
        XmeConfigureObject( (Widget) sw->swindow.hScrollBar, hsbX, hsbY,
		      sw->swindow.hsbWidth, 
		      sw->swindow.hScrollBar->core.height, SB_BORDER_WIDTH);
    else
        if (HSBExists)
        {
            XmeConfigureObject( (Widget) sw->swindow.hScrollBar,
                    sw->swindow.XOffset, sw->core.height, sw->swindow.hsbWidth,
                         sw->swindow.hScrollBar->core.height, SB_BORDER_WIDTH);
            if (_XmFocusIsHere( (Widget) sw->swindow.hScrollBar))
                XmProcessTraversal( (Widget) sw, XmTRAVERSE_NEXT_TAB_GROUP);
        }
    
    if (VSBExists) sw->swindow.vsbX = sw->swindow.vScrollBar->core.x;
    if (HSBExists) sw->swindow.hsbY = sw->swindow.hScrollBar->core.y;
}





/************************************************************************
 *									*
 * HandleDrop:	does nothing special                    	        *
 *									*
 ************************************************************************/
/*ARGSUSED*/
static void 
HandleDrop(
          Widget	w,	/* unused */
          XtPointer	client_data, /* unused */
          XtPointer	call_data)
{
    XmDropProcCallback		DropProc;
    Widget			dc;
    Arg args[1] ;

    DropProc = (XmDropProcCallback)call_data;
    dc = DropProc->dragContext;
    XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
    XmDropTransferStart(dc, args, 1);
}



/*ARGSUSED*/
static void 
TimerEvent(
        XtPointer closure,
        XtIntervalId *id)	/* unused */
{
    AutoDragClosure * auto_clos = (AutoDragClosure *) closure ;
    XmScrollBarWidget scrb = (XmScrollBarWidget) auto_clos->widget ;
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) XtParent(scrb) ;
    unsigned char direction = auto_clos->direction;
    Boolean hit = False ;
    int value ;
    XmNavigatorDataRec nav_data ;
    int repeat_delay = 100 ;

    /* for now, I don't have the get_range for all navigators,
       so special case the scrollbar which I know */
    if (!XmIsScrollBar(auto_clos->widget)) return ;

    /* use XmScrollBar: value, increment, maximum, slider_size, minimum */

    if (direction == FORWARD) { 
	if ((scrb->scrollBar.value + scrb->scrollBar.increment) <= 
	    (scrb->scrollBar.maximum - scrb->scrollBar.slider_size))
	    value = scrb->scrollBar.value + scrb->scrollBar.increment ;
	else {
	    value = scrb->scrollBar.maximum - scrb->scrollBar.slider_size ;
	    hit = True ;
	}
    } else {
	if ((scrb->scrollBar.value - scrb->scrollBar.increment) >= 
	    scrb->scrollBar.minimum)
	    value = scrb->scrollBar.value - scrb->scrollBar.increment ;
	else {
	    value = scrb->scrollBar.minimum ;
	    hit = True ;
	}
    }

    nav_data.valueMask = NavValue ;
    
    /* possible value for direction: horizontal or vertical */
    if (scrb->scrollBar.orientation == XmHORIZONTAL) {
	nav_data.value.x = value ;
	nav_data.dimMask = NavigDimensionX ;
    } else  {
	nav_data.value.y = value ;
	nav_data.dimMask = NavigDimensionY ;
    }

    _XmSFUpdateNavigatorsValue ((Widget)sw, &nav_data, True);

    XSync (XtDisplay (scrb), False); /* needed ? */

    /* reactivate the timer with the same closure if not hit */
    if (!hit) {
	XtVaGetValues(auto_clos->widget, XmNrepeatDelay, &repeat_delay, NULL);
	sw->swindow.auto_drag_timer = XtAppAddTimeOut (
                                 XtWidgetToApplicationContext((Widget) scrb),
				 repeat_delay,
				 TimerEvent, closure);
    } else {
	/* free the closure and mark the timer as non existent */
	XtFree((char*) closure);
	sw->swindow.auto_drag_timer = 0 ;
    }
}


  
/*ARGSUSED*/
static void 
HandleDrag(
	   Widget	w,
	   XtPointer	client_data, /* unused */
	   XtPointer	call_data)
{
    XmDragProcCallback	dragProc = (XmDragProcCallback)call_data;
    int initial_delay = 250;
    AutoDragClosure * auto_clos;
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) XtParent(w) ;
    AutoDragRects rects = (AutoDragRects) sw -> swindow.auto_drag_rects;
    
    /* w is one of the scrollbar */

    if (dragProc->reason ==  XmCR_DROP_SITE_ENTER_MESSAGE) {
	/* add a start update so that scrollbar moves generating widget
	   configurations be bracketed for dropsite update. */
	       
	XmDropSiteStartUpdate(w);

 	/* if that fails, initial_delay will stay 250 */
	XtVaGetValues(w, XmNinitialDelay, &initial_delay, NULL);
	
	if (sw->swindow.auto_drag_timer == 0) {
	    sw->swindow.auto_drag_closure = auto_clos = 
			(AutoDragClosure *) XtMalloc(sizeof(AutoDragClosure)) ;
	    auto_clos->widget = w ;

	    /* Here we need to find in which direction to move.
	       This is done using a private protocol between the 
	       GetAutoDragRects procs and this function: each scrollbar is
	       a drop site with potentially multiple rectangles,
	       the first half of them define the backward scroll and the
	       second half the forward scroll. 
	       For now we only handle 2 rectangles, one top or left and
	       one bottom or right of the corresp. scrollbar */

	    /* see if the current location is in the first rectangle*/
	    /* don't bother checking num_rect */
	    if (POINT_IN_RECT(dragProc->x, dragProc->y, rects -> up) ||
		POINT_IN_RECT(dragProc->x, dragProc->y, rects -> left))
	      auto_clos->direction = BACKWARD ;
	    else 
	      auto_clos->direction = FORWARD ;

	    sw->swindow.auto_drag_timer = 
                    XtAppAddTimeOut (XtWidgetToApplicationContext(w),
				     initial_delay,
				     TimerEvent, (XtPointer) auto_clos);
	}
    } else 
	if (dragProc->reason ==  XmCR_DROP_SITE_LEAVE_MESSAGE) {
	    /* end the update when leaving the dropsite, which means
	       when all move have been completed */

	    XmDropSiteEndUpdate(w);

	    if (sw->swindow.auto_drag_timer) {
		XtRemoveTimeOut (sw->swindow.auto_drag_timer);
		XtFree(sw->swindow.auto_drag_closure); 
		sw->swindow.auto_drag_timer = 0 ;
	    }
	}
}

/************************************************************************
 *									*
 *  GetAutoDragRects class methods                                      * 
 *									*
 ************************************************************************/

static void 
GetHorRects(
	    Widget sw,
	    XRectangle ** hrect, 
	    Cardinal * num_hrect)
{
    Widget w ;
    XmScrolledWindowWidget scw = (XmScrolledWindowWidget) sw ;

    *num_hrect = 2 ;
    *hrect = (XRectangle *) XtMalloc(sizeof(XRectangle) * (*num_hrect)) ;

    /* The hor rectangles are the ones that horizontally auto scroll,
       they are defined by areas on the left and right of the
       workarea, e.g. the margins, the spacing, the scrollbars
       and the shadows */

    /* Both rects are computed using only the relative work_area or 
       clipwindow (in AUTO) location within the scrolled window: 
       this is the area between the widget and its parent frame.
       Then they need to be translated into the scrollbar coord system. */

    /* what id to use for the sw child frame */
   if (scw->swindow.ScrollPolicy == XmAPPLICATION_DEFINED) {
       w = scw->swindow.WorkWindow;
       if (!w) w = sw ; /* fallback */
   } else
        w = (Widget) scw->swindow.ClipWindow;

    /* The first rectangle is the one that makes the scrollbar goes left */
    (*hrect)[0].x = 0 - scw->swindow.hScrollBar->core.x ;
    (*hrect)[0].y = w->core.y - scw->swindow.hScrollBar->core.y ;
    (*hrect)[0].width = MAX(2, w->core.x) ;
    (*hrect)[0].height = w->core.height ;
	
    /* The second rectangle is the one that makes the scrollbar goes right */
    (*hrect)[1].x = w->core.x + w->core.width 
	- scw->swindow.hScrollBar->core.x ;
    (*hrect)[1].y = (*hrect)[0].y ;
    (*hrect)[1].width = sw->core.width - (*hrect)[1].x ;
    /* if width too small, set it to 2 *inside* the SW frame */
    if ((*hrect)[1].width <= 2) {
	(*hrect)[1].width = 2 ;
	(*hrect)[1].x -= 2 ;
    }
    (*hrect)[1].height = (*hrect)[0].height ;

}



static void 
GetVertRects(
	     Widget sw,
	     XRectangle ** vrect, 
	     Cardinal * num_vrect)
{
    Widget w ;
    XmScrolledWindowWidget scw = (XmScrolledWindowWidget) sw ;

    *num_vrect = 2 ;
    *vrect = (XRectangle *) XtMalloc(sizeof(XRectangle) * (*num_vrect)) ;

    /* The vertical rectangles are the ones that vertically auto scroll,
       they are defined by areas on the top and bottom of the
       workarea, e.g. the margins, the spacing, the scrollbars
       and the shadows */

    /* Both rects are computed using only the relative work_area or 
       clipwindow (in AUTO) location within the scrolled window: 
       this is the area between the widget and its parent frame.
       Then they need to be translated into the scrollbar coord system. */

    /* what id to use for the sw child frame */
   if (scw->swindow.ScrollPolicy == XmAPPLICATION_DEFINED) {
       w = scw->swindow.WorkWindow;
       if (!w) w = sw ; /* fallback */
   } else
        w = (Widget) scw->swindow.ClipWindow;

    /* The first rectangle is the one that makes the scrollbar goes up */
    (*vrect)[0].x = w->core.x - scw->swindow.vScrollBar->core.x ;
    (*vrect)[0].y = 0 - scw->swindow.vScrollBar->core.y ;
    (*vrect)[0].width = w->core.width ;
    (*vrect)[0].height = MAX(2, w->core.y) ;
	
    /* The second rectangle is the one that makes the scrollbar goes down */
    (*vrect)[1].x = (*vrect)[0].x ;
    (*vrect)[1].y = w->core.y + w->core.height 
	- scw->swindow.vScrollBar->core.y ;
    (*vrect)[1].width = (*vrect)[0].width ;
    (*vrect)[1].height = sw->core.height - (*vrect)[1].y ;

    /* if height too small, set it to 2 *inside* the SW frame */
    if ((*vrect)[1].height <= 2) {
	(*vrect)[1].height = 2 ;
	(*vrect)[1].y -= 2 ;
    }
}





/************************************************************************
 *									*
 *  UpdateAutoDrag						        *
 *    update the dropsite size or create them the first time	        * 
 *									*
 ************************************************************************/
static void 
UpdateAutoDrag(
        XmScrolledWindowWidget sw)
    
{
    Widget hsb = (Widget) sw->swindow.hScrollBar, 
           vsb = (Widget) sw->swindow.vScrollBar;
    Arg args[10] ;
    Cardinal n ;
    XRectangle *hrect, *vrect;
    Cardinal num_hrect, num_vrect ;
    AutoDragRects rects = (AutoDragRects) sw -> swindow.auto_drag_rects;
    
    /* Entering here we know we have valid dropsites, 
       we now update their size */

    /* Each drop site is associated with a scrollbar, it has
       2 rectangles corresponding to the areas (on both side
       of the workarea) that autoscrolls this scrollbar */

    if (hsb) {

	/* Get the 2 horizontal rectangles defining the drop site
	   for horizontal autoscroll using a class method, so that
	   subclasses can override them */

	XmScrolledWindowClassExt              *wcePtr;
	WidgetClass  wc = XtClass((Widget) sw);
	
	wcePtr = _XmGetScrolledWindowClassExtPtr(wc, NULLQUARK);
	  
	if (*wcePtr && (*wcePtr)->get_hor_rects) {   
	    (*((*wcePtr)->get_hor_rects)) ((Widget) sw, &hrect, &num_hrect) ;
	} else {
	    /* no extension found or an extension with NULL proc,
	       so use the standard one */
	    GetHorRects ((Widget) sw, &hrect, &num_hrect) ; 
	}
      
	n = 0 ;
	XtSetArg(args[n], XmNdropRectangles, hrect); n++ ;
	XtSetArg(args[n], XmNnumDropRectangles, num_hrect); n++ ;
	XmDropSiteUpdate(hsb, args, n);

	/* Assign drop data in auto_drag_rects */
	rects -> left = hrect[0];

#ifdef AUTODRAG_DEBUG
printf("hrect %d %d %d %d / %d %d %d %d \n", 
       hrect[0].x, hrect[0].y, hrect[0].width, hrect[0].height, 
       hrect[1].x, hrect[1].y, hrect[1].width, hrect[1].height);
#endif

	XtFree((char *)hrect);
    }
    
    if (vsb) {
	/* Get the 2 vertical rectangles defining the drop site
	   for vertical autoscroll using a class method, so that
	   subclasses can override them */

	XmScrolledWindowClassExt              *wcePtr;
	WidgetClass   wc = XtClass((Widget) sw);
	
	wcePtr = _XmGetScrolledWindowClassExtPtr(wc, NULLQUARK);
	  
	if (*wcePtr && (*wcePtr)->get_vert_rects) {   
	    (*((*wcePtr)->get_vert_rects)) ((Widget) sw, &vrect, &num_vrect) ;
	} else {
	    /* no extension found or an extension with NULL proc,
	       so use the standard one */
	    GetVertRects ((Widget) sw, &vrect, &num_vrect) ; 
	}
      
	n = 0 ;
	XtSetArg(args[n], XmNdropRectangles, vrect); n++ ;
	XtSetArg(args[n], XmNnumDropRectangles, num_vrect); n++ ;
	XmDropSiteUpdate(vsb, args, n);

	/* Assign drop data in auto_drag_rects */
	rects -> up = vrect[0];

#ifdef AUTODRAG_DEBUG
printf("vrect %d %d %d %d / %d %d %d %d \n", 
       vrect[0].x, vrect[0].y, vrect[0].width, vrect[0].height, 
       vrect[1].x, vrect[1].y, vrect[1].width, vrect[1].height);
#endif

	XtFree((char *)vrect);
    }
}
  

/************************************************************************
 *
 *  Destroy
 *	Clean up allocated resources when the widget is destroyed.
 *
 ************************************************************************/
static void 
Destroy(
        Widget wid )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;

    if (sw->swindow.scroll_frame_inited) {
        if (sw->swindow.scroll_frame_data->nav_list)
	    XtFree((char*)sw->swindow.scroll_frame_data->nav_list);
	XtFree((char*)sw->swindow.scroll_frame_data);
    }

    if (sw->swindow.auto_drag_rects) 
      XtFree((char*) sw->swindow.auto_drag_rects);
}



/************************************************************************
 *									*
 *  Resize								*
 *  Recompute the size of the scrolled window.				* 
 *  Also update the auto Drag drop site rectangles                      *
 *  This function also clears the window and reexpose, so SetValues     *
 *  doesn't have to return True if it is going to resize.               *
 *									*
 ************************************************************************/
static void 
Resize(
        Widget wid )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    
    if (sw->swindow.VisualPolicy == XmVARIABLE)
        VariableLayout(sw);
    else
        ConstantLayout(sw);

    /* very expensive, redo that asap */
    if (XtIsRealized (wid)) {
	XClearArea(XtDisplay(wid), XtWindow(wid), 0, 0, 
		   XtWidth(wid),XtHeight(wid), True);
	
    }
    

    if (sw->swindow.auto_drag_model == XmAUTO_DRAG_ENABLED) {
	UpdateAutoDrag(sw);
    }
}



/************************************************************************
 *									*
 * GetVariableSize - Figure out the size of the scrolledwindow based 	*
 *		on the current scrollbar + workwindow sizes.    	*
 *		non zero value for passed argument mean don't touch     *
 *									*
 ************************************************************************/
static void 
GetVariableSize(
        XmScrolledWindowWidget sw,
	Dimension *pwidth,
        Dimension *pheight)
{
    XmScrollBarWidget	hsb = sw->swindow.hScrollBar, 
                        vsb = sw->swindow.vScrollBar;
    Widget 	    w = sw->swindow.WorkWindow;
    Dimension	    hsheight,vswidth;
    Dimension       hsbht = 0, vsbht = 0,
                    shads = sw->manager.shadow_thickness * 2;

    
    if (ExistManaged(w)) {
	if (ExistManaged((Widget) vsb)) {
	    vsbht = 2 * vsb->primitive.highlight_thickness;
	    vswidth = vsb->core.width + sw->swindow.pad + vsbht;
	} else vswidth = 0;

	if (ExistManaged((Widget) hsb)) {
	    hsbht = 2 * hsb->primitive.highlight_thickness;
	    hsheight = hsb->core.height + sw->swindow.pad + hsbht;
	} else hsheight = 0;

	if (!*pwidth)
	    *pwidth = w->core.width + (2 * w->core.border_width) + vswidth + 
		shads + hsbht + sw->swindow.XOffset + sw->swindow.WidthPad;
        if (!*pheight)
	    *pheight = w->core.height + (2*w->core.border_width) + hsheight + 
	    shads + vsbht + sw->swindow.YOffset + sw->swindow.HeightPad;
    } else {
	if (!*pwidth) *pwidth = sw->core.width;	
        if (!*pheight) *pheight = sw->core.height;
    }

    /* might still be null */
    if (!*pwidth) *pwidth = DEFAULT_SIZE ;
    if (!*pheight) *pheight = DEFAULT_SIZE ;

}




/************************************************************************
 *									*
 *  GeometryManager							*
 *									*
 ************************************************************************/
static XtGeometryResult 
GeometryManager(
        Widget w,
        XtWidgetGeometry *request,
        XtWidgetGeometry *reply )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget ) w->core.parent;
    XmScrollBarWidget hsb, vsb;
    XtGeometryResult  retval = XtGeometryNo;
    Dimension	    newWidth,newHeight;
    Dimension       hsheight,vswidth;
    Dimension       hsbht, vsbht, bw, ht;
    XtWidgetGeometry  parent_request ;
    XmScrolledWindowConstraint swc = GetSWConstraint(w);

    CheckKids(sw);
    
    hsbht = vsbht = 0;
    reply->request_mode = 0;
    ht = sw->manager.shadow_thickness * 2;
    hsb = sw->swindow.hScrollBar;
    vsb = sw->swindow.vScrollBar;

/****************
 *
 * Check the generic child: allow any position and size.
 * Application is responsible for proper geometry related to
 * scrollbars, clipwindow, etc. Application knows the layout
 * rules with margins, spacing, etc.
 * App also need to track the resize because generic children are
 * just ignored byt he SW.
 * Scrollbar requests that move or resize the sb in their allocated
 * area are treated as always yes, it's the appli responsabily
 * to not screw up the layout.
 * this doesn't handle multiple requests: both width and height for instance.
 ****************/
    if ((swc->child_type == XmGENERIC_CHILD) ||
	((w  == (Widget) vsb) && (request->request_mode & CWY)) ||
	((w  == (Widget) vsb) && (request->request_mode & CWHeight)) ||
	((w  == (Widget) hsb) && (request->request_mode & CWX)) ||
	((w  == (Widget) hsb) && (request->request_mode & CWWidth)))
	{
	if (!IsQueryOnly(request)) {

	    if (IsX(request)) w->core.x = request->x;
	    if (IsY(request)) w->core.y = request->y;
	    if (IsWidth(request)) w->core.width = request->width;
	    if (IsHeight(request)) w->core.height = request->height;
	    if (IsBorder(request)) w->core.border_width = 
		request->border_width;
	}
	return XtGeometryYes;
    }
    
    
/****************
 *
 * Carry forward that ugly wart for scrolled primitives...
 *
 ****************/
    
    if (ExistManaged((Widget) vsb))
    {
	vsbht = 2 * vsb->primitive.highlight_thickness;
        if (ExistManaged(sw->swindow.WorkWindow)        &&
            XmIsPrimitive(sw->swindow.WorkWindow)           &&
	    !(XmIsTraversable((Widget)sw->swindow.vScrollBar)))
	    vsbht = 0;
	vswidth = vsb->core.width + sw->swindow.pad + vsbht;
    }
    else
	vswidth = 0;

    if (ExistManaged((Widget) hsb))
    {
	hsbht = 2 * hsb->primitive.highlight_thickness;
        if (ExistManaged(sw->swindow.WorkWindow)        &&
            XmIsPrimitive(sw->swindow.WorkWindow)           &&
	    !(XmIsTraversable((Widget)sw->swindow.hScrollBar)))
	    hsbht = 0;
	hsheight = hsb->core.height + sw->swindow.pad + hsbht;
    }
    else
	hsheight = 0;
	
/****************
 *
 * Scrollbars 
 ****************/
 
    /* we've allowed the other case before, deny this one */
    if ((w  == (Widget) vsb) && (request->request_mode & CWX))
        return( XtGeometryNo);
    if ((w  == (Widget) hsb) && (request->request_mode & CWY))
        return(XtGeometryNo);

    /* always deny borderwidth changes, too much work for nothing */
    if (((w  == (Widget) hsb) || (w  == (Widget) hsb)) && 
	(request->request_mode & CWBorderWidth))
        return(XtGeometryNo);  /* border apply to both dimensions */


    if (((w == (Widget) hsb) && ((Dimension)w->core.y < sw->core.height)) || 
	((w == (Widget) vsb) && ((Dimension)w->core.x < sw->core.width))) {
	/* Visible scrollbar request */

	/* we already eliminated the bad case */
	if(request->request_mode & CWWidth)
	    newWidth = sw->core.width - w->core.width + request->width;
	else
	    newWidth = sw->core.width ;

	if(request->request_mode & CWHeight)
	    newHeight = sw->core.height - w->core.height + request->height;
	else
	    newHeight = sw->core.height ;

	parent_request.request_mode = CWWidth | CWHeight;
	parent_request.width = newWidth ;
	parent_request.height = newHeight ;

	/* Stop here in the QueryOnly case */
        if (request->request_mode & XtCWQueryOnly) {
	    parent_request.request_mode |= XtCWQueryOnly;
	    return XtMakeGeometryRequest((Widget) sw, &parent_request, NULL);
	}

	/* else it's for real */
	retval = _XmMakeGeometryRequest((Widget) sw, &parent_request);

	if (retval == XtGeometryYes) {
	    XtWidgetProc resize;

	    /* update the child geometry fields */
	    if (request->request_mode & CWBorderWidth)
		w->core.border_width = request->border_width;
	    if (request->request_mode & CWWidth)
		w->core.width = request->width;
	    if (request->request_mode & CWHeight)
		w->core.height = request->height;

	    /* relayout moi - maybe need an instigator param here? */
	    _XmProcessLock();
	    resize = XtCoreProc(sw, resize);
	    _XmProcessUnlock();
	    (*resize) ((Widget) sw) ;
	}
	return(retval);

    } else if ((w == (Widget) hsb) || (w == (Widget) vsb)) {  
	/* Invisible scrollbar ok request */
	if (!(request->request_mode & XtCWQueryOnly)) {
	    if (request->request_mode & CWBorderWidth)
		w->core.border_width = request->border_width;
	    if (request->request_mode & CWWidth)
		w->core.width = request->width;
	    if (request->request_mode & CWHeight)
		w->core.height = request->height;
	    if (request->request_mode & CWX)
		w->core.x = request->x;
	    if (request->request_mode & CWY)
		w->core.y = request->y;
	}
	return XtGeometryYes;
    }


    /**********************
     *  ELSE IT COMES FROM THE WORKWINDOW
     **********************/
      

    /* APPLICATION_DEFINED: try to grow the SW */
    if (sw->swindow.VisualPolicy == XmVARIABLE) {

	if (request->request_mode & CWBorderWidth)
	    bw = (request->border_width * 2);
	else
	    bw = (w->core.border_width * 2);

	if(request->request_mode & CWWidth)
	    newWidth = request->width + vswidth + ht + bw + hsbht
	               + sw->swindow.XOffset + sw->swindow.WidthPad ;
	else
            newWidth = w->core.width + vswidth + ht + bw + hsbht
	               + sw->swindow.XOffset + sw->swindow.WidthPad ;

	if(request->request_mode & CWHeight)
	    newHeight = request->height + hsheight + ht + bw + vsbht 
	                + sw->swindow.YOffset + sw->swindow.HeightPad ;
	else
            newHeight = w->core.height + hsheight + ht + bw + vsbht 
	                + sw->swindow.YOffset + sw->swindow.HeightPad;

        parent_request.request_mode = CWWidth | CWHeight;
	parent_request.width = newWidth ;
	parent_request.height = newHeight ;

	/* Stop here in the QueryOnly case */
        if (request->request_mode & XtCWQueryOnly) {
  	    parent_request.request_mode |= XtCWQueryOnly;
	    return XtMakeGeometryRequest((Widget) sw, &parent_request, NULL);
	}

	/* else it's for real */
	retval = _XmMakeGeometryRequest((Widget) sw, &parent_request);

	if (retval == XtGeometryYes) {
	    XtWidgetProc resize;

	    /* update the child geometry fields */
	    if (request->request_mode & CWBorderWidth)
		w->core.border_width = request->border_width;
	    if (request->request_mode & CWWidth)
		w->core.width = request->width;
	    if (request->request_mode & CWHeight)
		w->core.height = request->height;

	    /* relayout moi - maybe need an instigator param here ? */
	    if (!XmIsMainWindow(sw)) {
		_XmProcessLock();
		resize = XtCoreProc(sw, resize);
		_XmProcessUnlock();
		(*resize) ((Widget) sw);
	    }
	}
	return(retval);
    } 
    /* AUTOMATIC doesn't go thru here anymore, but use a trait */

    return XtGeometryNo;
}


/************************************************************************
 *
 *  UpdateOrigGeom trait method
 *
 *************************************<->***********************************/
static void
UpdateOrigGeom(Widget sf, Widget child, XtWidgetGeometry *geom)
{
  _XmSWNotifyGeoChange(sf, child, geom);
}


/************************************************************************
 *									*
 *  	_XmSWNotifyGeoChange	                                        *
 *        Used by the ClipWindow geometry manager.                      *
 *        could spare a trait method here, but that would add to the    *
 *        scrollFrame set, which has enough.                             *
 *									*
 ************************************************************************/
void
_XmSWNotifyGeoChange(
        Widget sw,
        Widget child,
        XtWidgetGeometry *request)
{
    /* called from ClipW GM and ChangeManage */
    XtWidgetProc resize;
    
    if (child) {
	XmScrolledWindowConstraint swc = GetSWConstraint(child);
	/* child is the ClipWindow child */

	/* reset original/set child position */
	if (request->request_mode & CWX) {
	    swc->orig_x = request->x ;
	}

	if (request->request_mode & CWY) {
	    swc->orig_y = request->y ;
	} 
    } 

    /* Just call Layout, which does all the scrollbars management */
    
    if (XtIsRealized(sw)) {
	_XmProcessLock();
	resize = XtCoreProc(sw, resize);
	_XmProcessUnlock();
	(*resize)(sw) ;
    }
}




/************************************************************************
 *									*
 *  ChangeManaged - called whenever there is a change in the managed	*
 *		    set.						*
 *									*
 ************************************************************************/
static void 
ChangeManaged(
        Widget wid )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    XtWidgetGeometry desired ;
    XtWidgetProc resize;
    
    if (sw->swindow.FromResize) return;

    CheckKids(sw);

    if (sw->swindow.VisualPolicy == XmVARIABLE) {
	/* the first time, only attemps to change non specified sizes */
	if (!XtIsRealized(wid))  {
	    desired.width = XtWidth(wid) ;   /* might be 0 */
	    desired.height = XtHeight(wid) ; /* might be 0 */
	} else {
	    desired.width = 0 ;
	    desired.height = 0 ;
	}
	GetVariableSize(sw, &desired.width, &desired.height);
        desired.request_mode = (CWWidth | CWHeight);
	(void) _XmMakeGeometryRequest(wid, &desired);
    }

    _XmProcessLock();
    resize = XtCoreProc(sw, resize);
    _XmProcessUnlock();
    (*resize) (wid) ;

    XmeNavigChangeManaged(wid);
}
     

/************************************************************************
 *									*
 *  QueryGeometry - Query proc for the scrolled window.			*
 *									*
 *  This routine will examine the geometry passed in an recalculate our	*
 *  width/height as follows:  if either the width or height is set, we	*
 *  take that as our new size, and figure out the other dimension to be	*
 *  the minimum size we need to be to display the entire child.  Note	*
 *  that this will only happen in auto mode, with as_needed display 	*
 *  policy.								*
 *									*
 ************************************************************************/
static XtGeometryResult 
QueryGeometry(
        Widget wid,
        XtWidgetGeometry *request,
        XtWidgetGeometry *ret )
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) wid ;
    Dimension	       MyWidth, MyHeight, KidHeight, KidWidth;
    Widget 	       w;
    XmScrollBarWidget  hsb, vsb;
    Dimension          hsheight,vswidth;
    Dimension	       hsbht, vsbht, ht;
    XtWidgetGeometry   desired, preferred;
    XtGeometryResult retval = XtGeometryYes;

    ret -> request_mode = 0;
    w = sw->swindow.WorkWindow;
    hsb = sw->swindow.hScrollBar;
    vsb = sw->swindow.vScrollBar;

/****************
 *
 * If the request mode is zero, fill out out default height & width.
 *
 ****************/
    if (request->request_mode == 0)
    {
        if ((sw->swindow.VisualPolicy == XmCONSTANT) ||
            (!sw->swindow.WorkWindow))
        {
	    ret->width = sw->core.width;	
            ret->height = sw->core.height;
    	    ret->request_mode = (CWWidth | CWHeight);
	    return (XtGeometryAlmost);
        }
        hsbht = vsbht = 0;
        ht = sw->manager.shadow_thickness * 2;

        desired.request_mode = 0;
        XtQueryGeometry(sw->swindow.WorkWindow, &desired, &preferred);

        KidWidth = preferred.width;
        KidHeight = preferred.height;
        if (ExistManaged((Widget) vsb)) 
        {
            vsbht = 2 * vsb->primitive.highlight_thickness;
	    vswidth = vsb->core.width + sw->swindow.pad + vsbht;
        }
        else
	    vswidth = 0;

        if (ExistManaged((Widget) hsb)) 
        {
	    hsbht = 2 * hsb->primitive.highlight_thickness;
	    hsheight = hsb->core.height + sw->swindow.pad + hsbht;
        }
        else
	    hsheight = 0;
	
        if (ExistManaged(w)) 
        {
            ret->width = KidWidth + (2 * w->core.border_width) + vswidth + 
	           ht + hsbht + sw->swindow.XOffset + sw->swindow.WidthPad;
            ret->height = KidHeight  + (2 * w->core.border_width) + hsheight + 
	            ht + vsbht + sw->swindow.YOffset + sw->swindow.HeightPad;
        }
        else
        {
	    ret->width = sw->core.width;	
            ret->height = sw->core.height;
        }
        ret->request_mode = (CWWidth | CWHeight);
	return (XtGeometryAlmost);
    }

/****************
 *
 * If app mode, or static scrollbars, or no visible kid, 
 * accept the new size, and return our current size for any 
 * missing dimension.
 *
 ****************/
    if ((sw->swindow.ScrollPolicy == XmAPPLICATION_DEFINED) ||
	(!ExistManaged(w)))
    {
        if (!(request -> request_mode & CWWidth))
        {
    	    ret->request_mode |= CWWidth;
            ret->width = sw->core.width;
	    retval = XtGeometryAlmost;
	}
        if (!(request -> request_mode & CWHeight))
        {
            ret->request_mode |= CWHeight;
            ret->height = sw->core.height;
            retval = XtGeometryAlmost;
        }
        return(retval);
    }

/****************
 *
 * Else look for the specified dimension, and set the other size so that we
 * just enclose the child. 
 * If the new size would cause us to lose the scrollbar, figure
 * out the other dimension as well and return that, too.
 *
 ****************/

    hsbht = vsbht = 0;
    ht = sw->manager.shadow_thickness * 2;
    hsb = sw->swindow.hScrollBar;
    vsb = sw->swindow.vScrollBar;

    if ((request -> request_mode & CWWidth) &&
        (request -> request_mode & CWHeight)&&
        (sw->swindow.ScrollBarPolicy == XmAS_NEEDED))
    {
        ret->height = w->core.height + (2 * w->core.border_width) +
	              ht + sw->swindow.YOffset + sw->swindow.HeightPad;
        ret->width = w->core.width + (2 * w->core.border_width) +
                     ht + sw->swindow.XOffset + sw->swindow.WidthPad;
        ret->request_mode |= (CWWidth | CWHeight);
        return(XtGeometryAlmost);
    }

    if (request -> request_mode & CWHeight)
    {

        MyHeight = request->height - sw->swindow.YOffset - 
	           sw->swindow.HeightPad - ht;

        if (((w->core.height + (2 * w->core.border_width)) > MyHeight) ||
            (sw->swindow.ScrollBarPolicy == XmSTATIC))
        {
   	    vsbht = 2 * vsb->primitive.highlight_thickness;
	    vswidth = vsb->core.width + sw->swindow.pad;
        }
        else
        {
	    vswidth = 0;
            ret->request_mode |= CWHeight;
            ret->height = w->core.height + (2 * w->core.border_width) +
	             ht + sw->swindow.YOffset + sw->swindow.HeightPad;
        }

        ret->request_mode |= CWWidth;
        ret->width = w->core.width + (2 * w->core.border_width) + vswidth + 
	             ht + vsbht + sw->swindow.XOffset + sw->swindow.WidthPad;
	retval = XtGeometryAlmost;
    }

    if (request -> request_mode & CWWidth)
    {
        MyWidth = request->width - sw->swindow.XOffset - 
	           sw->swindow.WidthPad - ht;

        if (((w->core.width + (2 * w->core.border_width)) > MyWidth) ||
            (sw->swindow.ScrollBarPolicy == XmSTATIC))
        {
   	    hsbht = 2 * hsb->primitive.highlight_thickness;
	    hsheight = hsb->core.height + sw->swindow.pad;
        }
        else
        {
	    hsheight = 0;
            ret->request_mode |= CWWidth;
            ret->width = w->core.width + (2 * w->core.border_width) +
	                 ht + sw->swindow.XOffset + sw->swindow.WidthPad;
        }

        ret->request_mode |= CWHeight;
        ret->height = w->core.height + (2 * w->core.border_width) + hsheight + 
	             ht + hsbht + sw->swindow.YOffset + sw->swindow.HeightPad;
	retval = XtGeometryAlmost;
    }

    return(retval);
}


/************************************************************************
 *									*
 *  SetValues								*
 *									*
 ************************************************************************/
/*ARGSUSED*/
static Boolean 
SetValues(
        Widget cw,
        Widget rw,
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
    XmScrolledWindowWidget current = (XmScrolledWindowWidget) cw ;
    XmScrolledWindowWidget request = (XmScrolledWindowWidget) rw ;
    XmScrolledWindowWidget new_w = (XmScrolledWindowWidget) nw ;
    Boolean Flag = FALSE;

    /*******************
     * check validity first 
     *******************/     

    CheckKids(new_w);

    if(!XmRepTypeValidValue( XmRID_SCROLL_BAR_DISPLAY_POLICY,
			    new_w->swindow.ScrollBarPolicy, (Widget) new_w))
    {
	new_w->swindow.ScrollBarPolicy = current->swindow.ScrollBarPolicy;
    }	

    if (request->swindow.ScrollPolicy != current->swindow.ScrollPolicy)
    {
	XmeWarning( (Widget) new_w, SWMessage6);
	new_w->swindow.ScrollPolicy = current->swindow.ScrollPolicy;
    }

    if (request->swindow.VisualPolicy != current->swindow.VisualPolicy)
    {
	XmeWarning( (Widget) new_w, SWMessage7);
	new_w->swindow.VisualPolicy = current->swindow.VisualPolicy;
    }

    if ((new_w->swindow.VisualPolicy == XmVARIABLE) &&
	(request->swindow.ScrollBarPolicy == XmAS_NEEDED))
    {
	XmeWarning( (Widget) new_w, SWMessage8);
	new_w->swindow.ScrollBarPolicy = XmSTATIC;
    }

    if (new_w->swindow.ScrollPolicy == XmAUTOMATIC)
    {
    	if (new_w->swindow.hScrollBar != current->swindow.hScrollBar)
	{
	    XmeWarning( (Widget) new_w, SWMessage9);
	    new_w->swindow.hScrollBar = current->swindow.hScrollBar;	
	}
    	if (new_w->swindow.vScrollBar != current->swindow.vScrollBar)
	{
	    XmeWarning( (Widget) new_w, SWMessage9);
	    new_w->swindow.vScrollBar = current->swindow.vScrollBar;	
	}
    }

    if (new_w->swindow.ClipWindow != current->swindow.ClipWindow)
    {
	XmeWarning( (Widget) new_w, SWMessage10);
	new_w->swindow.ClipWindow = current->swindow.ClipWindow;
    }
    
    if(!XmRepTypeValidValue( XmRID_SCROLL_BAR_PLACEMENT,
			    new_w->swindow.Placement, (Widget) new_w))
    {
	new_w->swindow.Placement = current->swindow.Placement;
    }	


    /* In AUTOMATIC, we explicitly forbid changing the workArea,
       because the clipWindow reparenting can't be undone or done at this
       point.
       The only way to swicth between workArea is to destroy the current one,
       which would set it to NULL internally, and recreate it so
       that InsertChild takes it 
    
    if (new_w->swindow.ScrollPolicy == XmAUTOMATIC) {
    	if (new_w->swindow.WorkWindow != current->swindow.WorkWindow) {
	    XmeWarning((Widget) new_w, SWMessage2);
	    new_w->swindow.WorkWindow = current->swindow.WorkWindow;	
	}
    }*/

    /*******************
     * then check if there needs to be a relayout of the internals 
     * Here we choose not to grow or shrink the SW if one of those
     * change, we just relayout everything in the current boundaries.
     ********************/
    if ((new_w->swindow.WidthPad != current->swindow.WidthPad) ||
        (new_w->swindow.HeightPad != current->swindow.HeightPad) ||
        (new_w->manager.shadow_thickness!=current->manager.shadow_thickness)||
        (new_w->swindow.pad != current->swindow.pad) ||
	(new_w->swindow.Placement != current->swindow.Placement)  ||
	(new_w->swindow.ScrollBarPolicy != current->swindow.ScrollBarPolicy))
	{
	    XtWidgetProc resize;

            new_w->swindow.XOffset = new_w->swindow.WidthPad;
            new_w->swindow.YOffset = new_w->swindow.HeightPad;
	    /* relayout moi, resize will rexpose as well */
	    _XmProcessLock();
	    resize = XtCoreProc(new_w, resize);
	    _XmProcessUnlock();
	    (*resize)(nw) ;
	}


    /* the following can only happen in APP_DEFINED mode */
    if ((new_w->swindow.hScrollBar != current->swindow.hScrollBar)||
	(new_w->swindow.vScrollBar != current->swindow.vScrollBar)||
	(new_w->swindow.WorkWindow != current->swindow.WorkWindow)) {

	/* set our core geometry to the needed size - 
	   no resizePolicy here... 
	   See comment in MainW.c for this realized check */
	if (XtIsRealized((Widget)new_w)) {
	    new_w->core.width = 0 ;
	    new_w->core.height = 0 ;
	    GetVariableSize(new_w, &new_w->core.width, &new_w->core.height);
	}
    }

    if (new_w->swindow.auto_drag_model != current->swindow.auto_drag_model) {
	
	if (new_w->swindow.auto_drag_model == XmAUTO_DRAG_ENABLED) {
	    Arg s_args[5];
	    Cardinal n ;

	    /* moving from disable to enable, allocate the rects the
	       first time thru */
	    if (new_w->swindow.auto_drag_rects == NULL) 
		new_w->swindow.auto_drag_rects = 
		  XtCalloc(1, sizeof(AutoDragRectsRec));

	    /* reinstall the D&D callback on the potential scrollbars */
	    n = 0 ;
	    XtSetArg(s_args[n], XmNdropProc, HandleDrop), n++ ;
	    XtSetArg(s_args[n], XmNdragProc, HandleDrag), n++ ;
	    XtSetArg(s_args[n], XmNnumImportTargets, 1), n++ ;
	    XtSetArg(s_args[n], XmNimportTargets, new_w), n++ ;
	    assert(n <= XtNumber(s_args));
	    if (new_w->swindow.hScrollBar) 
		XmDropSiteRegister((Widget)new_w->swindow.hScrollBar, 
				   s_args, n);
	    if (new_w->swindow.vScrollBar) 
		XmDropSiteRegister((Widget)new_w->swindow.vScrollBar, 
				   s_args, n);
	} else {
	    /* moving from enable to disable, unregister the d&d site
	       but leave the drag_rect around */
	    if (new_w->swindow.hScrollBar) 
		XmDropSiteUnregister((Widget)new_w->swindow.hScrollBar);
	    if (new_w->swindow.vScrollBar) 
		XmDropSiteUnregister((Widget)new_w->swindow.vScrollBar);
	}
    }
      
    return (Flag);
}


/************************************************************************
 *
 *  Constraint Initialize
 *
 *************************************<->***********************************/
/*ARGSUSED*/
static void 
ConstraintInitialize(
        Widget rw,		/* unused */
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
   XmScrolledWindowConstraint swc;

   if (!XtIsRectObj (nw)) return;

   swc = GetSWConstraint(nw);

   if ((swc->child_type != (unsigned char) RESOURCE_DEFAULT) &&
       (!XmRepTypeValidValue(XmRID_SCROLLED_WINDOW_CHILD_TYPE, 
			     swc->child_type, nw)))
   {
      swc->child_type = (unsigned char) RESOURCE_DEFAULT;
   }

   /* for all children, get their original position.
      It actually only matter for clipped children, but quicker this way */
   swc->orig_x = nw->core.x ;
   swc->orig_y = nw->core.y ;
}

/***************************************
   No ConstraintSetValues.  Because of the reparenting to the clipwindow,
   it won't be called in all cases anyway. ClipWindow could get one,
   and here one as well, with the only benefit to reject wrong
   childType setting, not worth it IHMO. The tracking od the set position
   is done in the ClipWindow geometry manager for the clipped kid, which
   calls the notifygeochange API
 ***************************************/
 

/************************************************************************
 *
 *  ScrollFrame Init trait method
 *
 *************************************<->***********************************/
static void 
ScrollFrameInit (
		 Widget sf, 
		 XtCallbackProc moveCB,
		 Widget scrollable)
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) sf ;
    
    if (sw->swindow.scroll_frame_inited) return ;

    sw->swindow.scroll_frame_inited = True ;

    sw->swindow.scroll_frame_data = (XmScrollFrameData)
	XtMalloc(sizeof(XmScrollFrameDataRec));

    sw->swindow.scroll_frame_data->num_nav_list = 0 ;
    sw->swindow.scroll_frame_data->nav_list = NULL ;
    sw->swindow.scroll_frame_data->num_nav_slots = 0 ;

    sw->swindow.scroll_frame_data->move_cb = moveCB ;
    sw->swindow.scroll_frame_data->scrollable = scrollable ;
}
    


/************************************************************************
 *
 *  GetInfo
 *	scrolledwindow is a 2 dimensional frame.
 *
 ************************************************************************/
static Boolean
GetInfo(
	 Widget sf,
	 Cardinal * dimension,
	 Widget ** nav_list,
	 Cardinal * num_nav_list)
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) sf ;

    if (dimension) *dimension = 2 ;  /* two dimensional frame */

    if (sw->swindow.scroll_frame_inited) {

	if (nav_list) *nav_list = sw->swindow.scroll_frame_data->nav_list ;
	if (num_nav_list) 
	    *num_nav_list = sw->swindow.scroll_frame_data->num_nav_list ;
    }

    return sw->swindow.scroll_frame_inited ; 
}


/************************************************************************
 *
 *  AddNavigator trait method
 *
 *************************************<->***********************************/
static void 
AddNavigator(
    Widget sf,
    Widget nav,
    Mask dimMask)
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) sf ;
    
    /* check if already initialized scrollFrame */
    if (!sw->swindow.scroll_frame_inited) {
	XmScrollFrameTrait sf_trait = (XmScrollFrameTrait) 
	    XmeTraitGet((XtPointer) XtClass(sf), XmQTscrollFrame);

	/* not inited yet: it's a non ScrolledList/Text APP_DEFINED 
	   or AUTOMATIC scrolled window.
	   Initialize now, when the first navigator is added.
	   We cannot give any good move callback to install on the other
	   navigators, so use NULL. In this case, we rely on the navigators
	   to have their own callback prior to be added to the navigator list */
	sf_trait->init(sf, (XtCallbackProc) NULL, (Widget) NULL);
    }

    /* now scroll_frame_data is always valid */
    _XmSFAddNavigator(sf, nav, dimMask,  sw->swindow.scroll_frame_data);
}

/************************************************************************
 *
 *  RemoveNavigator trait method
 *
 *************************************<->***********************************/
static void 
RemoveNavigator(
    Widget sf,
    Widget nav)
{
    XmScrolledWindowWidget sw = (XmScrolledWindowWidget) sf ;

    if (sw->swindow.scroll_frame_inited) 
	_XmSFRemoveNavigator(sf, nav, sw->swindow.scroll_frame_data);
}

/************************************************************************
 *									*
 *  	_XmSWGetClipArea
 *        Used by the Traversal code.                                  
 *         - widget specifies a child of the clipwindow.
 *	   - rect returns the area of the clip window (in root window
 *	     coordinates) where that child can appear.
 *	   - returns True is successful, otherwise False.
 *    (For a clip window with only one work window this will 
 *     degenerate to the root bounds of the clip window itself)
 *
 ************************************************************************/

Boolean
_XmSWGetClipArea(Widget widget, 
		 XRectangle *rect) 
{
    XmClipWindowWidget clip = (XmClipWindowWidget) XtParent(widget);
    XmScrolledWindowWidget sw;
    Cardinal i ;
    Widget child ;
    XmScrolledWindowConstraint swc;
    Position root_x, root_y ;

    /* reality check */
    if (!clip || !XmIsClipWindow(clip)) return False ;
    sw = (XmScrolledWindowWidget) XtParent(clip);
    if (!sw) return False ;

    /* init with the clipwindow frame */
    rect->x = 0 ;
    rect->y = 0 ;
    rect->width = clip->core.width ;    
    rect->height = clip->core.height ;

    /* loop thru the clip children, and for each partially scrollable
       babie, modify the returned rect. This assumes a WORK_AREA (all
       scrollable) kid is the target, some SCROLL_HOR or VERT sibling 
       are obscuring it, and since we only return ONE rectangle, we 
       special case the header (y=0) or the first column (x=0) child */
    for (i = 0; i < clip->composite.num_children; i++) {
	child = clip->composite.children[i];
	if (ExistManaged(child)) {  
	    swc = GetSWConstraint(child);
	    if (swc->child_type == XmSCROLL_HOR) {
		/* this one doesn't move vertically. If its y is 0 
		   takes its height as the new y of our rectangle, if
		   its y is not 0, it becomes our rect height (everything
		   below its y is considered unaccessible) */
		if (child->core.y == 0) {
		    rect->y = child->core.height ;
		    rect->height -= child->core.height ;
		} else
		    rect->height = child->core.y ;
	    } else
	    if (swc->child_type == XmSCROLL_HOR) {
		/* same thing for x */
		if (child->core.x == 0) {
		    rect->x = child->core.width ;
		    rect->width -= child->core.width ;
		} else
		    rect->width = child->core.x ;
	    }
	}
    }

    /* root coordinates is wanted. (Xt doesn't seem to allow for
       rect to be passed in and out at the same time) */
    XtTranslateCoords((Widget)clip, rect->x, rect->y, 
		      &root_x, &root_y);
    rect->x = root_x ;
    rect->y = root_y ;

    return True;
}

/************************************************************************
 *									*
 * Public API Functions							*
 *									*
 ************************************************************************/

/************************************************************************
 *									*
 * XmScrolledWindowSetAreas - set a new widget set.			*
 *		a NULL means: don't change the parameter        	*
 *        - deprecated in favor of SetValues, which it uses             *
 ************************************************************************/
void 
XmScrolledWindowSetAreas(
        Widget w,
        Widget hscroll,
        Widget vscroll,
        Widget wregion )
{
    Arg args[5] ;
    Cardinal n;

    n = 0;
    if (hscroll) {
	XtSetArg (args[n], XmNhorizontalScrollBar, hscroll); n++;
    }
    if (vscroll) {
	XtSetArg (args[n], XmNverticalScrollBar, vscroll); n++;
    }
    if (wregion) {
	XtSetArg (args[n], XmNworkWindow, wregion); n++;
    }
    XtSetValues(w, args, n);    
}


/************************************************************************
 *									*
 * XmCreateScrolledWindow - hokey interface to XtCreateWidget.		*
 *									*
 ************************************************************************/
Widget 
XmCreateScrolledWindow(
        Widget parent,
        char *name,
        ArgList args,
        Cardinal argCount )
{

    return (XtCreateWidget(name, xmScrolledWindowWidgetClass, 
			   parent, args, argCount ));
}



/***************************************************************************
  DESIGN NOTES:
  
  InsertChild takes care of setting the internal scrollbar or workarea
  fields to the last inserted child.

  The previous kid might still be hanging around in the managed child list
  if the application hasn't done something about it. 

  In the regular case, one creates a SW, add kids and everything is fine.
  (and SetAreas or SetValues is a NoOp).
  If the appli creates another kid as the workarea for instance 
  (same problem for another scrollbar in APP_DEFINED), it becomes the 
  current workarea and it is on top by default - no problem.
  Now if the application switches the 2 workareas and reset the first one
  as the current workarea using XtSetValues, who is responsible for
  raising it on top (or lowering, or unmapping - the other) ?
  I'd say SetValues deals with that situation using RaiseWidget.

  When a child is deleted, if it is a current resource, the internal
  field is NULLed, otherwise, it is just deleted from the child list.
  (ChangeManaged is called for the relayout).

***************************************************************************/
