17a84e134Smrg/***********************************************************
27a84e134Smrg
37a84e134SmrgCopyright 1987, 1988, 1994, 1998  The Open Group
47a84e134Smrg
57a84e134SmrgPermission to use, copy, modify, distribute, and sell this software and its
67a84e134Smrgdocumentation for any purpose is hereby granted without fee, provided that
77a84e134Smrgthe above copyright notice appear in all copies and that both that
87a84e134Smrgcopyright notice and this permission notice appear in supporting
97a84e134Smrgdocumentation.
107a84e134Smrg
117a84e134SmrgThe above copyright notice and this permission notice shall be included in
127a84e134Smrgall copies or substantial portions of the Software.
137a84e134Smrg
147a84e134SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157a84e134SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167a84e134SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
177a84e134SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
187a84e134SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
197a84e134SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
207a84e134Smrg
217a84e134SmrgExcept as contained in this notice, the name of The Open Group shall not be
227a84e134Smrgused in advertising or otherwise to promote the sale, use or other dealings
237a84e134Smrgin this Software without prior written authorization from The Open Group.
247a84e134Smrg
257a84e134Smrg
267a84e134SmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
277a84e134Smrg
287a84e134Smrg                        All Rights Reserved
297a84e134Smrg
30421c997bSmrgPermission to use, copy, modify, and distribute this software and its
31421c997bSmrgdocumentation for any purpose and without fee is hereby granted,
327a84e134Smrgprovided that the above copyright notice appear in all copies and that
33421c997bSmrgboth that copyright notice and this permission notice appear in
347a84e134Smrgsupporting documentation, and that the name of Digital not be
357a84e134Smrgused in advertising or publicity pertaining to distribution of the
36421c997bSmrgsoftware without specific, written prior permission.
377a84e134Smrg
387a84e134SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
397a84e134SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
407a84e134SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
417a84e134SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
427a84e134SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
437a84e134SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
447a84e134SmrgSOFTWARE.
457a84e134Smrg
467a84e134Smrg******************************************************************/
477a84e134Smrg
487a84e134Smrg#ifdef HAVE_CONFIG_H
497a84e134Smrg#include <config.h>
507a84e134Smrg#endif
517a84e134Smrg#include <X11/IntrinsicP.h>
527a84e134Smrg#include <X11/StringDefs.h>
537a84e134Smrg#include <X11/Xmu/Misc.h>
547a84e134Smrg#include <X11/Xaw/Scrollbar.h>
557a84e134Smrg#include <X11/Xaw/ViewportP.h>
567a84e134Smrg#include <X11/Xaw/XawInit.h>
577a84e134Smrg#include "Private.h"
587a84e134Smrg
597a84e134Smrg/*
607a84e134Smrg * Class Methods
617a84e134Smrg */
627a84e134Smrgstatic Boolean Layout(FormWidget, unsigned int, unsigned int, Bool);
637a84e134Smrgstatic void XawViewportChangeManaged(Widget);
647a84e134Smrgstatic void XawViewportInitialize(Widget, Widget, ArgList, Cardinal*);
657a84e134Smrgstatic void
667a84e134SmrgXawViewportConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
677a84e134Smrgstatic XtGeometryResult XawViewportGeometryManager(Widget, XtWidgetGeometry*,
687a84e134Smrg						   XtWidgetGeometry*);
697a84e134Smrgstatic XtGeometryResult XawViewportQueryGeometry(Widget,
707a84e134Smrg						 XtWidgetGeometry*,
717a84e134Smrg						 XtWidgetGeometry*);
727a84e134Smrgstatic void XawViewportRealize(Widget, XtValueMask*, XSetWindowAttributes*);
737a84e134Smrgstatic void XawViewportResize(Widget);
747a84e134Smrgstatic Boolean XawViewportSetValues(Widget, Widget, Widget,
757a84e134Smrg				    ArgList, Cardinal*);
767a84e134Smrg
777a84e134Smrg/*
787a84e134Smrg * Prototypes
797a84e134Smrg */
807a84e134Smrgstatic void ComputeLayout(Widget, Bool, Bool);
817a84e134Smrgstatic void ComputeWithForceBars(Widget, Bool, XtWidgetGeometry*,
827a84e134Smrg				 int*, int*);
837a84e134Smrgstatic Widget CreateScrollbar(ViewportWidget, Bool);
847a84e134Smrgstatic XtGeometryResult GeometryRequestPlusScrollbar(ViewportWidget, Bool,
857a84e134Smrg						     XtWidgetGeometry*,
867a84e134Smrg						     XtWidgetGeometry*);
877a84e134Smrgstatic Bool GetGeometry(Widget, unsigned int, unsigned int);
887a84e134Smrgstatic void MoveChild(ViewportWidget, int, int);
897a84e134Smrgstatic XtGeometryResult QueryGeometry(ViewportWidget, XtWidgetGeometry*,
907a84e134Smrg				      XtWidgetGeometry*);
917a84e134Smrgstatic void RedrawThumbs(ViewportWidget);
927a84e134Smrgstatic void ScrollUpDownProc(Widget, XtPointer, XtPointer);
937a84e134Smrgstatic void SendReport(ViewportWidget, unsigned int);
947a84e134Smrgstatic void SetBar(Widget, int, unsigned int, unsigned int);
957a84e134Smrgstatic XtGeometryResult TestSmaller(ViewportWidget, XtWidgetGeometry*,
967a84e134Smrg				    XtWidgetGeometry*);
977a84e134Smrgstatic void ThumbProc(Widget, XtPointer, XtPointer);
987a84e134Smrg
997a84e134Smrg/*
1007a84e134Smrg * Initialization
1017a84e134Smrg */
1027a84e134Smrg#define offset(field) XtOffsetOf(ViewportRec, viewport.field)
1037a84e134Smrgstatic XtResource resources[] = {
1047a84e134Smrg  {
1057a84e134Smrg    XtNforceBars,
1067a84e134Smrg    XtCBoolean,
1077a84e134Smrg    XtRBoolean,
1087a84e134Smrg    sizeof(Boolean),
1097a84e134Smrg    offset(forcebars),
1107a84e134Smrg    XtRImmediate,
1117a84e134Smrg    (XtPointer)False
1127a84e134Smrg  },
1137a84e134Smrg  {
1147a84e134Smrg    XtNallowHoriz,
1157a84e134Smrg    XtCBoolean,
1167a84e134Smrg    XtRBoolean,
1177a84e134Smrg    sizeof(Boolean),
1187a84e134Smrg    offset(allowhoriz),
1197a84e134Smrg    XtRImmediate,
1207a84e134Smrg    (XtPointer)False
1217a84e134Smrg  },
1227a84e134Smrg  {
1237a84e134Smrg    XtNallowVert,
1247a84e134Smrg    XtCBoolean,
1257a84e134Smrg    XtRBoolean,
1267a84e134Smrg    sizeof(Boolean),
1277a84e134Smrg    offset(allowvert),
1287a84e134Smrg    XtRImmediate,
1297a84e134Smrg    (XtPointer)False
1307a84e134Smrg  },
1317a84e134Smrg  {
1327a84e134Smrg    XtNuseBottom,
1337a84e134Smrg    XtCBoolean,
1347a84e134Smrg    XtRBoolean,
1357a84e134Smrg    sizeof(Boolean),
1367a84e134Smrg    offset(usebottom),
1377a84e134Smrg    XtRImmediate,
1387a84e134Smrg    (XtPointer)False
1397a84e134Smrg  },
1407a84e134Smrg  {
1417a84e134Smrg    XtNuseRight,
1427a84e134Smrg    XtCBoolean,
1437a84e134Smrg    XtRBoolean,
1447a84e134Smrg    sizeof(Boolean),
1457a84e134Smrg    offset(useright),
1467a84e134Smrg    XtRImmediate,
1477a84e134Smrg    (XtPointer)False
1487a84e134Smrg  },
1497a84e134Smrg  {
1507a84e134Smrg    XtNreportCallback,
1517a84e134Smrg    XtCReportCallback,
1527a84e134Smrg    XtRCallback,
1537a84e134Smrg    sizeof(XtPointer),
1547a84e134Smrg    offset(report_callbacks),
1557a84e134Smrg    XtRImmediate,
1567a84e134Smrg    NULL
1577a84e134Smrg  },
1587a84e134Smrg};
1597a84e134Smrg#undef offset
1607a84e134Smrg
1617a84e134Smrg#define Superclass	(&formClassRec)
1627a84e134SmrgViewportClassRec viewportClassRec = {
1637a84e134Smrg  /* core */
1647a84e134Smrg  {
1657a84e134Smrg    (WidgetClass)Superclass,		/* superclass */
1667a84e134Smrg    "Viewport",				/* class_name */
1677a84e134Smrg    sizeof(ViewportRec),		/* widget_size */
1687a84e134Smrg    XawInitializeWidgetSet,		/* class_initialize */
1697a84e134Smrg    NULL,				/* class_part_init */
1707a84e134Smrg    False,				/* class_inited */
1717a84e134Smrg    XawViewportInitialize,		/* initialize */
1727a84e134Smrg    NULL,				/* initialize_hook */
1737a84e134Smrg    XawViewportRealize,			/* realize */
1747a84e134Smrg    NULL,				/* actions */
1757a84e134Smrg    0,					/* num_actions */
1767a84e134Smrg    resources,				/* resources */
1777a84e134Smrg    XtNumber(resources),		/* num_resources */
1787a84e134Smrg    NULLQUARK,				/* xrm_class */
1797a84e134Smrg    True,				/* compress_motion */
1807a84e134Smrg    True,				/* compress_exposure */
1817a84e134Smrg    True,				/* compress_enterleave */
1827a84e134Smrg    False,				/* visible_interest */
1837a84e134Smrg    NULL,				/* destroy */
1847a84e134Smrg    XawViewportResize,			/* resize */
1857a84e134Smrg    XtInheritExpose,			/* expose */
1867a84e134Smrg    XawViewportSetValues,		/* set_values */
1877a84e134Smrg    NULL,				/* set_values_hook */
1887a84e134Smrg    XtInheritSetValuesAlmost,		/* set_values_almost */
1897a84e134Smrg    NULL,				/* get_values_hook */
1907a84e134Smrg    NULL,				/* accept_focus */
1917a84e134Smrg    XtVersion,				/* version */
1927a84e134Smrg    NULL,				/* callback_private */
1937a84e134Smrg    NULL,				/* tm_table */
1947a84e134Smrg    XawViewportQueryGeometry,		/* query_geometry */
1957a84e134Smrg    XtInheritDisplayAccelerator,	/* display_accelerator */
1967a84e134Smrg    NULL,				/* extension */
1977a84e134Smrg  },
1987a84e134Smrg  /* composite */
1997a84e134Smrg  {
2007a84e134Smrg    XawViewportGeometryManager,		/* geometry_manager */
2017a84e134Smrg    XawViewportChangeManaged,		/* change_managed */
2027a84e134Smrg    XtInheritInsertChild,		/* insert_child */
2037a84e134Smrg    XtInheritDeleteChild,		/* delete_child */
2047a84e134Smrg    NULL,				/* extension */
2057a84e134Smrg  },
2067a84e134Smrg  /* constraint */
2077a84e134Smrg  {
2087a84e134Smrg    NULL,				/* subresourses */
2097a84e134Smrg    0,					/* subresource_count */
2107a84e134Smrg    sizeof(ViewportConstraintsRec),	/* constraint_size */
2117a84e134Smrg    XawViewportConstraintInitialize,	/* initialize */
2127a84e134Smrg    NULL,				/* destroy */
2137a84e134Smrg    NULL,				/* set_values */
2147a84e134Smrg    NULL,				/* extension */
2157a84e134Smrg  },
2167a84e134Smrg  /* form */
2177a84e134Smrg  {
2187a84e134Smrg    Layout,				/* layout */
219efbcb2bfSmrg#ifndef OLDXAW
220efbcb2bfSmrg    NULL,
221efbcb2bfSmrg#endif
2227a84e134Smrg  },
2237a84e134Smrg  /* viewport */
2247a84e134Smrg  {
2257a84e134Smrg    NULL,				/* extension */
2267a84e134Smrg  },
2277a84e134Smrg};
2287a84e134Smrg
2297a84e134SmrgWidgetClass viewportWidgetClass = (WidgetClass)&viewportClassRec;
2307a84e134Smrg
2317a84e134Smrg/*
2327a84e134Smrg * Implementation
2337a84e134Smrg */
2347a84e134Smrgstatic Widget
2357a84e134SmrgCreateScrollbar(ViewportWidget w, Bool horizontal)
2367a84e134Smrg{
2377a84e134Smrg    static Arg barArgs[] = {
2387a84e134Smrg	{XtNorientation,	    0},
2397a84e134Smrg	{XtNlength,		    0},
2407a84e134Smrg	{XtNleft,		    0},
2417a84e134Smrg	{XtNright,		    0},
2427a84e134Smrg	{XtNtop,		    0},
2437a84e134Smrg	{XtNbottom,		    0},
2447a84e134Smrg	{XtNmappedWhenManaged,	    False},
2457a84e134Smrg    };
2467a84e134Smrg    Widget clip = w->viewport.clip;
2477a84e134Smrg    ViewportConstraints constraints =
2487a84e134Smrg	(ViewportConstraints)clip->core.constraints;
2497a84e134Smrg    Widget bar;
2507a84e134Smrg
2517a84e134Smrg    XtSetArg(barArgs[0], XtNorientation,
2527a84e134Smrg	   horizontal ? XtorientHorizontal : XtorientVertical);
2537a84e134Smrg    XtSetArg(barArgs[1], XtNlength,
2547a84e134Smrg	   horizontal ? XtWidth(clip) : XtHeight(clip));
2557a84e134Smrg    XtSetArg(barArgs[2], XtNleft,
2567a84e134Smrg	   !horizontal && w->viewport.useright ? XtChainRight : XtChainLeft);
2577a84e134Smrg    XtSetArg(barArgs[3], XtNright,
2587a84e134Smrg	   !horizontal && !w->viewport.useright ? XtChainLeft : XtChainRight);
2597a84e134Smrg    XtSetArg(barArgs[4], XtNtop,
2607a84e134Smrg	   horizontal && w->viewport.usebottom ? XtChainBottom: XtChainTop);
2617a84e134Smrg    XtSetArg(barArgs[5], XtNbottom,
2627a84e134Smrg	   horizontal && !w->viewport.usebottom ? XtChainTop: XtChainBottom);
2637a84e134Smrg
2647a84e134Smrg    bar = XtCreateWidget(horizontal ? "horizontal" : "vertical",
2657a84e134Smrg			 scrollbarWidgetClass, (Widget)w,
2667a84e134Smrg			 barArgs, XtNumber(barArgs));
2677a84e134Smrg    XtAddCallback(bar, XtNscrollProc, ScrollUpDownProc, (XtPointer)w);
2687a84e134Smrg    XtAddCallback(bar, XtNjumpProc, ThumbProc, (XtPointer)w);
2697a84e134Smrg
2707a84e134Smrg    if (horizontal) {
2717a84e134Smrg	w->viewport.horiz_bar = bar;
2727a84e134Smrg	constraints->form.vert_base = bar;
2737a84e134Smrg    }
2747a84e134Smrg    else {
2757a84e134Smrg	w->viewport.vert_bar = bar;
2767a84e134Smrg	constraints->form.horiz_base = bar;
2777a84e134Smrg    }
2787a84e134Smrg
2797a84e134Smrg    XtManageChild(bar);
2807a84e134Smrg
2817a84e134Smrg    return (bar);
2827a84e134Smrg}
2837a84e134Smrg
2847a84e134Smrg/*ARGSUSED*/
2857a84e134Smrgstatic void
2865ec34c4cSmrgXawViewportInitialize(Widget request _X_UNUSED, Widget cnew,
2875ec34c4cSmrg		      ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
2887a84e134Smrg{
2897a84e134Smrg    ViewportWidget w = (ViewportWidget)cnew;
2907a84e134Smrg    static Arg clip_args[8];
2917a84e134Smrg    Cardinal arg_cnt;
2927a84e134Smrg    Widget h_bar, v_bar;
2937a84e134Smrg    Dimension clip_height, clip_width;
2947a84e134Smrg
2957a84e134Smrg    w->form.default_spacing = 0; /* Reset the default spacing to 0 pixels */
2967a84e134Smrg
2977a84e134Smrg    /*
2987a84e134Smrg     * Initialize all widget pointers to NULL
2997a84e134Smrg     */
3007a84e134Smrg    w->viewport.child = NULL;
3017a84e134Smrg    w->viewport.horiz_bar = w->viewport.vert_bar = NULL;
3027a84e134Smrg
3037a84e134Smrg    /*
3047a84e134Smrg     * Create Clip Widget
3057a84e134Smrg     */
3067a84e134Smrg    arg_cnt = 0;
3077a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNbackgroundPixmap, None);	arg_cnt++;
3087a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNborderWidth, 0);		arg_cnt++;
3097a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNleft, XtChainLeft);		arg_cnt++;
3107a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNright, XtChainRight);	arg_cnt++;
3117a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNtop, XtChainTop);		arg_cnt++;
3127a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNbottom, XtChainBottom);	arg_cnt++;
3137a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNwidth, XtWidth(w));		arg_cnt++;
3147a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNheight, XtHeight(w));	arg_cnt++;
3157a84e134Smrg
3167a84e134Smrg    w->viewport.clip = XtCreateManagedWidget("clip", widgetClass, cnew,
3177a84e134Smrg					     clip_args, arg_cnt);
3187a84e134Smrg
319421c997bSmrg    if (!w->viewport.forcebars)
3207a84e134Smrg	return;		 /* If we are not forcing the bars then we are done */
3217a84e134Smrg
322421c997bSmrg    if (w->viewport.allowhoriz)
3237a84e134Smrg	(void)CreateScrollbar(w, True);
324421c997bSmrg    if (w->viewport.allowvert)
3257a84e134Smrg	(void)CreateScrollbar(w, False);
3267a84e134Smrg
3277a84e134Smrg    h_bar = w->viewport.horiz_bar;
3287a84e134Smrg    v_bar = w->viewport.vert_bar;
3297a84e134Smrg
3307a84e134Smrg    /*
3317a84e134Smrg     * Set the clip widget to the correct height
3327a84e134Smrg     */
3337a84e134Smrg    clip_width = XtWidth(w);
3347a84e134Smrg    clip_height = XtHeight(w);
3357a84e134Smrg
3367a84e134Smrg    if (h_bar != NULL &&  XtWidth(w) > XtWidth(h_bar) + XtBorderWidth(h_bar))
3375ec34c4cSmrg	clip_width = (Dimension)(clip_width - (XtWidth(h_bar) + XtBorderWidth(h_bar)));
3387a84e134Smrg
3397a84e134Smrg    if (v_bar != NULL && XtHeight(w) > XtHeight(v_bar) + XtBorderWidth(v_bar))
3405ec34c4cSmrg	clip_height = (Dimension)(clip_height - (XtHeight(v_bar) + XtBorderWidth(v_bar)));
3417a84e134Smrg
3427a84e134Smrg    arg_cnt = 0;
3437a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNwidth, clip_width); arg_cnt++;
3447a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNheight, clip_height); arg_cnt++;
3457a84e134Smrg    XtSetValues(w->viewport.clip, clip_args, arg_cnt);
3467a84e134Smrg}
3477a84e134Smrg
3487a84e134Smrg/*ARGSUSED*/
3497a84e134Smrgstatic void
3505ec34c4cSmrgXawViewportConstraintInitialize(Widget request _X_UNUSED, Widget cnew,
3515ec34c4cSmrg				ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
3527a84e134Smrg{
3537a84e134Smrg    ((ViewportConstraints)cnew->core.constraints)->viewport.reparented = False;
3547a84e134Smrg}
3557a84e134Smrg
3567a84e134Smrgstatic void
3577a84e134SmrgXawViewportRealize(Widget widget, XtValueMask *value_mask,
3587a84e134Smrg		   XSetWindowAttributes *attributes)
3597a84e134Smrg{
3607a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
3617a84e134Smrg    Widget child = w->viewport.child;
3627a84e134Smrg    Widget clip = w->viewport.clip;
3637a84e134Smrg
3647a84e134Smrg    *value_mask |= CWBitGravity;
3657a84e134Smrg    attributes->bit_gravity = NorthWestGravity;
3667a84e134Smrg    (*Superclass->core_class.realize)(widget, value_mask, attributes);
3677a84e134Smrg
3687a84e134Smrg    (*w->core.widget_class->core_class.resize)(widget);	/* turn on bars */
3697a84e134Smrg
3707a84e134Smrg    if (child != NULL) {
3717a84e134Smrg	XtMoveWidget(child, 0, 0);
3727a84e134Smrg	XtRealizeWidget(clip);
3737a84e134Smrg	XtRealizeWidget(child);
3747a84e134Smrg	XReparentWindow(XtDisplay(w), XtWindow(child), XtWindow(clip), 0, 0);
3757a84e134Smrg	XtMapWidget(child);
3767a84e134Smrg    }
3777a84e134Smrg}
3787a84e134Smrg
3797a84e134Smrg/*ARGSUSED*/
3807a84e134Smrgstatic Boolean
3815ec34c4cSmrgXawViewportSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
3825ec34c4cSmrg		     ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
3837a84e134Smrg{
3847a84e134Smrg    ViewportWidget w = (ViewportWidget)cnew;
3857a84e134Smrg    ViewportWidget cw = (ViewportWidget)current;
3867a84e134Smrg
3877a84e134Smrg    if (w->viewport.forcebars != cw->viewport.forcebars
3887a84e134Smrg	|| w->viewport.allowvert != cw->viewport.allowvert
3897a84e134Smrg	|| w->viewport.allowhoriz != cw->viewport.allowhoriz
3907a84e134Smrg	|| w->viewport.useright != cw->viewport.useright
3917a84e134Smrg	|| w->viewport.usebottom != cw->viewport.usebottom)
3927a84e134Smrg	(*w->core.widget_class->core_class.resize)(cnew); /* Recompute layout */
3937a84e134Smrg
3947a84e134Smrg    return (False);
3957a84e134Smrg}
3967a84e134Smrg
3977a84e134Smrgstatic void
3987a84e134SmrgXawViewportChangeManaged(Widget widget)
3997a84e134Smrg{
4007a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
4015ec34c4cSmrg    int num_children = (int)w->composite.num_children;
4027a84e134Smrg    Widget child, *childP;
4037a84e134Smrg    int i;
4047a84e134Smrg
4057a84e134Smrg    child = NULL;
4067a84e134Smrg    for (childP = w->composite.children,
4077a84e134Smrg	 i = 0; i < num_children;
4087a84e134Smrg	 childP++, i++) {
4097a84e134Smrg	if (XtIsManaged(*childP)
4107a84e134Smrg	    && *childP != w->viewport.clip
4117a84e134Smrg	    && *childP != w->viewport.horiz_bar
4127a84e134Smrg	    && *childP != w->viewport.vert_bar)	{
4137a84e134Smrg	    child = *childP;
4147a84e134Smrg	    break;
4157a84e134Smrg	}
4167a84e134Smrg    }
4177a84e134Smrg
4187a84e134Smrg    if (child != w->viewport.child) {
4197a84e134Smrg	w->viewport.child = child;
4207a84e134Smrg	if (child != NULL) {
4217a84e134Smrg	    XtResizeWidget(child, XtWidth(child), XtHeight(child), 0);
4227a84e134Smrg	    if (XtIsRealized(widget)) {
4237a84e134Smrg		ViewportConstraints constraints =
4247a84e134Smrg		    (ViewportConstraints)child->core.constraints;
4257a84e134Smrg		if (!XtIsRealized(child)) {
4267a84e134Smrg		    Window window = XtWindow(w);
4277a84e134Smrg
4287a84e134Smrg		    XtMoveWidget(child, 0, 0);
4297a84e134Smrg		    w->core.window = XtWindow(w->viewport.clip);
4307a84e134Smrg		    XtRealizeWidget(child);
4317a84e134Smrg		    w->core.window = window;
4327a84e134Smrg		    constraints->viewport.reparented = True;
4337a84e134Smrg		}
4347a84e134Smrg		else if (!constraints->viewport.reparented) {
4357a84e134Smrg		    XReparentWindow(XtDisplay(w), XtWindow(child),
4367a84e134Smrg				    XtWindow(w->viewport.clip), 0, 0);
4377a84e134Smrg		    constraints->viewport.reparented = True;
4387a84e134Smrg		    if (child->core.mapped_when_managed)
4397a84e134Smrg		    XtMapWidget(child);
4407a84e134Smrg		}
4417a84e134Smrg	    }
4427a84e134Smrg	    GetGeometry(widget, XtWidth(child), XtHeight(child));
4437a84e134Smrg	    (*((ViewportWidgetClass)w->core.widget_class)->form_class.layout)
4447a84e134Smrg	    ((FormWidget)w, XtWidth(w), XtHeight(w), True /* True? */);
4457a84e134Smrg	}
4467a84e134Smrg    }
4477a84e134Smrg}
4487a84e134Smrg
4497a84e134Smrgstatic void
4507a84e134SmrgSetBar(Widget w, int top, unsigned int length, unsigned int total)
4517a84e134Smrg{
4527a84e134Smrg    XawScrollbarSetThumb(w, (float)top / (float)total,
4537a84e134Smrg			 (float)length / (float)total);
4547a84e134Smrg}
4557a84e134Smrg
4567a84e134Smrgstatic void
4577a84e134SmrgRedrawThumbs(ViewportWidget w)
4587a84e134Smrg{
4597a84e134Smrg    Widget child = w->viewport.child;
4607a84e134Smrg    Widget clip = w->viewport.clip;
4617a84e134Smrg
4627a84e134Smrg    if (w->viewport.horiz_bar != NULL)
4637a84e134Smrg	SetBar(w->viewport.horiz_bar, -(int)XtX(child),
4647a84e134Smrg	       XtWidth(clip), XtWidth(child));
4657a84e134Smrg
4667a84e134Smrg    if (w->viewport.vert_bar != NULL)
4677a84e134Smrg	SetBar(w->viewport.vert_bar, -(int)XtY(child),
4687a84e134Smrg	       XtHeight(clip), XtHeight(child));
4697a84e134Smrg}
4707a84e134Smrg
4717a84e134Smrgstatic void
4727a84e134SmrgSendReport(ViewportWidget w, unsigned int changed)
4737a84e134Smrg{
4747a84e134Smrg    if (w->viewport.report_callbacks) {
4757a84e134Smrg	Widget child = w->viewport.child;
4767a84e134Smrg	Widget clip = w->viewport.clip;
477efbcb2bfSmrg	XawPannerReport rep = {
478efbcb2bfSmrg	    .changed = changed,
479efbcb2bfSmrg	    .slider_x = (Position) -XtX(child),	/* child is canvas */
480efbcb2bfSmrg	    .slider_y = (Position) -XtY(child),	/* clip is slider */
481efbcb2bfSmrg	    .slider_width = XtWidth(clip),
482efbcb2bfSmrg	    .slider_height = XtHeight(clip),
483efbcb2bfSmrg	    .canvas_width = XtWidth(child),
484efbcb2bfSmrg	    .canvas_height = XtHeight(child)
485efbcb2bfSmrg	};
4867a84e134Smrg	XtCallCallbackList((Widget)w, w->viewport.report_callbacks,
4877a84e134Smrg			   (XtPointer)&rep);
4887a84e134Smrg    }
4897a84e134Smrg}
4907a84e134Smrg
4917a84e134Smrgstatic void
4927a84e134SmrgMoveChild(ViewportWidget w, int x, int y)
4937a84e134Smrg{
4947a84e134Smrg    Widget child = w->viewport.child;
4957a84e134Smrg    Widget clip = w->viewport.clip;
4967a84e134Smrg
4977a84e134Smrg    /* make sure we never move past right/bottom borders */
4987a84e134Smrg    if (-x + (int)XtWidth(clip) > XtWidth(child))
4997a84e134Smrg	x = -(int)(XtWidth(child) - XtWidth(clip));
5007a84e134Smrg
5017a84e134Smrg    if (-y + (int)XtHeight(clip) > XtHeight(child))
5027a84e134Smrg	y = -(int)(XtHeight(child) - XtHeight(clip));
5037a84e134Smrg
5047a84e134Smrg    /* make sure we never move past left/top borders */
5057a84e134Smrg    if (x >= 0)
5067a84e134Smrg	x = 0;
5077a84e134Smrg    if (y >= 0)
5087a84e134Smrg	y = 0;
5097a84e134Smrg
5105ec34c4cSmrg    XtMoveWidget(child, (Position) x, (Position) y);
5117a84e134Smrg    SendReport(w, (XawPRSliderX | XawPRSliderY));
5127a84e134Smrg
5137a84e134Smrg    RedrawThumbs(w);
5147a84e134Smrg}
5157a84e134Smrg
5167a84e134Smrgstatic void
5177a84e134SmrgComputeLayout(Widget widget, Bool query, Bool destroy_scrollbars)
5187a84e134Smrg{
5197a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
5207a84e134Smrg    Widget child = w->viewport.child;
5217a84e134Smrg    Widget clip = w->viewport.clip;
5227a84e134Smrg    ViewportConstraints constraints =
5237a84e134Smrg	(ViewportConstraints)clip->core.constraints;
5247a84e134Smrg    Bool needshoriz, needsvert;
5257a84e134Smrg    int clip_width, clip_height;
5267a84e134Smrg    XtWidgetGeometry intended;
5277a84e134Smrg
5287a84e134Smrg    if (child == NULL)
5297a84e134Smrg	return;
5307a84e134Smrg
5317a84e134Smrg    clip_width = XtWidth(w);
5327a84e134Smrg    clip_height = XtHeight(w);
5337a84e134Smrg    intended.request_mode = CWBorderWidth;
5347a84e134Smrg    intended.border_width = 0;
5357a84e134Smrg
5367a84e134Smrg    if (w->viewport.forcebars) {
5377a84e134Smrg	needsvert = w->viewport.allowvert;
5387a84e134Smrg	needshoriz = w->viewport.allowhoriz;
539421c997bSmrg	ComputeWithForceBars(widget, query, &intended,
5407a84e134Smrg			     &clip_width, &clip_height);
5417a84e134Smrg    }
5427a84e134Smrg    else {
5437a84e134Smrg	Dimension prev_width, prev_height;
5447a84e134Smrg	XtGeometryMask prev_mode;
5457a84e134Smrg	XtWidgetGeometry preferred;
5467a84e134Smrg
5477a84e134Smrg	needshoriz = needsvert = False;
5487a84e134Smrg
5497a84e134Smrg	/*
5507a84e134Smrg	 * intended.{width,height} caches the eventual child dimensions,
5517a84e134Smrg	 * but we don't set the mode bits until after we decide that the
5527a84e134Smrg	 * child's preferences are not acceptable
5537a84e134Smrg	 */
554421c997bSmrg	if (!w->viewport.allowhoriz)
5557a84e134Smrg	    intended.request_mode |= CWWidth;
5567a84e134Smrg
5577a84e134Smrg	if (XtWidth(child) < clip_width)
5585ec34c4cSmrg	    intended.width = (Dimension)clip_width;
5597a84e134Smrg	else
5607a84e134Smrg	    intended.width = XtWidth(child);
5617a84e134Smrg
5627a84e134Smrg	if (XtHeight(child) < clip_height)
5635ec34c4cSmrg	    intended.height = (Dimension)clip_height;
5647a84e134Smrg	else
5657a84e134Smrg	    intended.height = XtHeight(child);
5667a84e134Smrg
567421c997bSmrg	if (!w->viewport.allowvert)
5687a84e134Smrg	    intended.request_mode |= CWHeight;
5697a84e134Smrg
5707a84e134Smrg	if (!query) {
5717a84e134Smrg	    preferred.width = XtWidth(child);
5727a84e134Smrg	    preferred.height = XtHeight(child);
5737a84e134Smrg	}
5747a84e134Smrg	do { /* while intended != prev  */
5757a84e134Smrg	    if (query) {
5767a84e134Smrg		(void)XtQueryGeometry(child, &intended, &preferred);
5777a84e134Smrg		if (!(preferred.request_mode & CWWidth))
5787a84e134Smrg		    preferred.width = intended.width;
5797a84e134Smrg		if (!(preferred.request_mode & CWHeight))
5807a84e134Smrg		    preferred.height = intended.height;
5817a84e134Smrg	    }
5827a84e134Smrg	    prev_width = intended.width;
5837a84e134Smrg	    prev_height = intended.height;
5847a84e134Smrg	    prev_mode = intended.request_mode;
5857a84e134Smrg	    /*
5867a84e134Smrg	     * note that having once decided to turn on either bar
5877a84e134Smrg	     * we'll not change our mind until we're next resized,
5887a84e134Smrg	     * thus avoiding potential oscillations
5897a84e134Smrg	     */
5907a84e134Smrg#define CheckHoriz() \
5917a84e134Smrg	    if (w->viewport.allowhoriz &&				\
5927a84e134Smrg		preferred.width > clip_width) {				\
5937a84e134Smrg		if (!needshoriz) {					\
5945ec34c4cSmrg		    Widget bar2;					\
5957a84e134Smrg									\
5967a84e134Smrg		    needshoriz = True;					\
5975ec34c4cSmrg		    if ((bar2 = w->viewport.horiz_bar) == NULL)		\
5985ec34c4cSmrg			bar2 = CreateScrollbar(w, True);		\
5995ec34c4cSmrg		    clip_height -= XtHeight(bar2) + XtBorderWidth(bar2);\
6007a84e134Smrg		    if (clip_height < 1)				\
6017a84e134Smrg			clip_height = 1;				\
6027a84e134Smrg		}							\
6037a84e134Smrg		intended.width = preferred.width;			\
6047a84e134Smrg	    }
6057a84e134Smrg
6067a84e134Smrg	    CheckHoriz();
6077a84e134Smrg	    if (w->viewport.allowvert && preferred.height > clip_height) {
6087a84e134Smrg		if (!needsvert) {
6097a84e134Smrg		    Widget bar;
6107a84e134Smrg		    needsvert = True;
6117a84e134Smrg		    if ((bar = w->viewport.vert_bar) == NULL)
6127a84e134Smrg			bar = CreateScrollbar(w, False);
6137a84e134Smrg		    clip_width -= XtWidth(bar) + XtBorderWidth(bar);
6147a84e134Smrg		    if (clip_width < 1)
6157a84e134Smrg			clip_width = 1;
6167a84e134Smrg		    CheckHoriz();
6177a84e134Smrg		}
6187a84e134Smrg		intended.height = preferred.height;
6197a84e134Smrg	    }
6207a84e134Smrg	    if (!w->viewport.allowhoriz || preferred.width < clip_width) {
6215ec34c4cSmrg		intended.width = (Dimension)clip_width;
6227a84e134Smrg		intended.request_mode |= CWWidth;
6237a84e134Smrg	    }
6247a84e134Smrg	    if (!w->viewport.allowvert || preferred.height < clip_height) {
6255ec34c4cSmrg		intended.height = (Dimension)clip_height;
6267a84e134Smrg		intended.request_mode |= CWHeight;
6277a84e134Smrg	    }
6287a84e134Smrg	} while (intended.request_mode != prev_mode
6297a84e134Smrg		 || (intended.request_mode & CWWidth
6307a84e134Smrg		     && intended.width != prev_width)
6317a84e134Smrg		 || (intended.request_mode & CWHeight
6327a84e134Smrg		     && intended.height != prev_height));
6337a84e134Smrg    }
6347a84e134Smrg
6357a84e134Smrg    if (XtIsRealized(clip))
6367a84e134Smrg	XRaiseWindow(XtDisplay(clip), XtWindow(clip));
6377a84e134Smrg
6387a84e134Smrg    XtMoveWidget(clip,
6395ec34c4cSmrg		 (Position)(needsvert ? w->viewport.useright ? 0 :
6405ec34c4cSmrg					XtWidth(w->viewport.vert_bar)
6415ec34c4cSmrg			    + XtBorderWidth(w->viewport.vert_bar) : 0),
6425ec34c4cSmrg		 (Position)(needshoriz ? w->viewport.usebottom ? 0 :
6435ec34c4cSmrg					 XtHeight(w->viewport.horiz_bar)
6445ec34c4cSmrg			    + XtBorderWidth(w->viewport.horiz_bar) : 0));
6455ec34c4cSmrg    XtResizeWidget(clip, (Dimension)clip_width, (Dimension)clip_height, 0);
646421c997bSmrg
6477a84e134Smrg    if (w->viewport.horiz_bar != NULL) {
6487a84e134Smrg	Widget bar = w->viewport.horiz_bar;
6497a84e134Smrg
6507a84e134Smrg	if (!needshoriz) {
6517a84e134Smrg	    constraints->form.vert_base = NULL;
6527a84e134Smrg	    if (destroy_scrollbars) {
6537a84e134Smrg		XtDestroyWidget(bar);
6547a84e134Smrg		w->viewport.horiz_bar = NULL;
6557a84e134Smrg	    }
6567a84e134Smrg	}
6577a84e134Smrg	else {
6587a84e134Smrg	    int bw = XtBorderWidth(bar);
6597a84e134Smrg
6605ec34c4cSmrg	    XtResizeWidget(bar, (Dimension)clip_width, (Dimension)XtHeight(bar), (Dimension)bw);
6617a84e134Smrg	    XtMoveWidget(bar,
6625ec34c4cSmrg			 (Position)(needsvert && !w->viewport.useright
6635ec34c4cSmrg				    ? XtWidth(w->viewport.vert_bar) : -bw),
6645ec34c4cSmrg			 (Position)(w->viewport.usebottom
6655ec34c4cSmrg				    ? XtHeight(w) - XtHeight(bar) - bw : -bw));
6667a84e134Smrg	    XtSetMappedWhenManaged(bar, True);
6677a84e134Smrg	}
6687a84e134Smrg    }
6697a84e134Smrg
6707a84e134Smrg    if (w->viewport.vert_bar != NULL) {
6717a84e134Smrg	Widget bar = w->viewport.vert_bar;
6727a84e134Smrg
6737a84e134Smrg	if (!needsvert)	{
6747a84e134Smrg	    constraints->form.horiz_base = NULL;
6757a84e134Smrg	    if (destroy_scrollbars) {
6767a84e134Smrg		XtDestroyWidget(bar);
6777a84e134Smrg		w->viewport.vert_bar = NULL;
6787a84e134Smrg	    }
6797a84e134Smrg	}
6807a84e134Smrg	else {
6817a84e134Smrg	    int bw = bar->core.border_width;
6827a84e134Smrg
6835ec34c4cSmrg	    XtResizeWidget(bar, (Dimension)XtWidth(bar), (Dimension)clip_height, (Dimension)bw);
6847a84e134Smrg	    XtMoveWidget(bar,
6855ec34c4cSmrg			(Position)(w->viewport.useright
6865ec34c4cSmrg				   ? XtWidth(w) - XtWidth(bar) - bw : -bw),
6875ec34c4cSmrg			(Position)(needshoriz && !w->viewport.usebottom
6885ec34c4cSmrg				   ? XtHeight(w->viewport.horiz_bar) : -bw));
6897a84e134Smrg	   XtSetMappedWhenManaged(bar, True);
6907a84e134Smrg	}
6917a84e134Smrg    }
6927a84e134Smrg
6937a84e134Smrg    if (child != NULL) {
6947a84e134Smrg	XtResizeWidget(child, intended.width, intended.height, 0);
6957a84e134Smrg	MoveChild(w, needshoriz ? XtX(child) : 0,	needsvert ? XtY(child) : 0);
6967a84e134Smrg    }
6977a84e134Smrg
6987a84e134Smrg    SendReport (w, XawPRAll);
6997a84e134Smrg}
7007a84e134Smrg
7017a84e134Smrg/*
7027a84e134Smrg * Function:
7037a84e134Smrg *	ComputeWithForceBars
7047a84e134Smrg *
7057a84e134Smrg * Parameters:
7067a84e134Smrg *	widget	    - viewport widget
7077a84e134Smrg *	query	    - whether or not to query the child
7085b16253fSmrg *	intended    - cache of the child's height is stored here
7097a84e134Smrg *		      (used and returned)
7107a84e134Smrg *	clip_width  - size of clip window (used and returned)
7117a84e134Smrg *	clip_height - ""
7127a84e134Smrg *
7137a84e134Smrg * Description:
7147a84e134Smrg *	Computes the layout give forcebars is set.
7157a84e134Smrg */
7167a84e134Smrgstatic void
7177a84e134SmrgComputeWithForceBars(Widget widget, Bool query, XtWidgetGeometry *intended,
7187a84e134Smrg		     int *clip_width, int *clip_height)
7197a84e134Smrg{
7207a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
7217a84e134Smrg    Widget child = w->viewport.child;
7227a84e134Smrg    XtWidgetGeometry preferred;
7237a84e134Smrg
7247a84e134Smrg    /*
7257a84e134Smrg     * If forcebars then needs = allows = has
7267a84e134Smrg     * Thus if needsvert is set it MUST have a scrollbar
7277a84e134Smrg     */
7287a84e134Smrg    if (w->viewport.allowvert) {
729421c997bSmrg	if (w->viewport.vert_bar == NULL)
7307a84e134Smrg	    w->viewport.vert_bar = CreateScrollbar(w, False);
7317a84e134Smrg
7327a84e134Smrg	*clip_width -= XtWidth(w->viewport.vert_bar) +
7337a84e134Smrg		       XtBorderWidth(w->viewport.vert_bar);
7347a84e134Smrg    }
7357a84e134Smrg
7367a84e134Smrg    if (w->viewport.allowhoriz) {
737421c997bSmrg	if (w->viewport.horiz_bar == NULL)
7387a84e134Smrg	    w->viewport.horiz_bar = CreateScrollbar(w, True);
7397a84e134Smrg
7407a84e134Smrg	*clip_height -= XtHeight(w->viewport.horiz_bar) +
7417a84e134Smrg			XtBorderWidth(w->viewport.horiz_bar);
7427a84e134Smrg    }
7437a84e134Smrg
7447a84e134Smrg    AssignMax(*clip_width, 1);
7457a84e134Smrg    AssignMax(*clip_height, 1);
7467a84e134Smrg
7477a84e134Smrg    if (!w->viewport.allowvert) {
7485ec34c4cSmrg	intended->height = (Dimension)*clip_height;
7497a84e134Smrg	intended->request_mode = CWHeight;
7507a84e134Smrg    }
7517a84e134Smrg    if (!w->viewport.allowhoriz) {
7525ec34c4cSmrg	intended->width = (Dimension)*clip_width;
7537a84e134Smrg	intended->request_mode = CWWidth;
7547a84e134Smrg    }
7557a84e134Smrg
7567a84e134Smrg    if (query) {
7577a84e134Smrg	if (w->viewport.allowvert || w->viewport.allowhoriz) {
7587a84e134Smrg	    XtQueryGeometry(child, intended, &preferred);
759421c997bSmrg
7607a84e134Smrg	    if (!(intended->request_mode & CWWidth)) {
7617a84e134Smrg		if (preferred.request_mode & CWWidth)
7627a84e134Smrg		    intended->width = preferred.width;
7637a84e134Smrg		else
7647a84e134Smrg		    intended->width = XtWidth(child);
7657a84e134Smrg	    }
7667a84e134Smrg
7677a84e134Smrg	    if (!(intended->request_mode & CWHeight)) {
7687a84e134Smrg		if (preferred.request_mode & CWHeight)
7697a84e134Smrg		    intended->height = preferred.height;
7707a84e134Smrg		else
7717a84e134Smrg		    intended->height = XtHeight(child);
7727a84e134Smrg	    }
7737a84e134Smrg	}
7747a84e134Smrg    }
7757a84e134Smrg    else {
7767a84e134Smrg	if (w->viewport.allowvert)
7777a84e134Smrg	    intended->height = XtHeight(child);
7787a84e134Smrg	if (w->viewport.allowhoriz)
7797a84e134Smrg	    intended->width = XtWidth(child);
7807a84e134Smrg    }
7817a84e134Smrg
7827a84e134Smrg    if (*clip_width > (int)intended->width)
7835ec34c4cSmrg	intended->width = (Dimension)*clip_width;
7847a84e134Smrg    if (*clip_height > (int)intended->height)
7855ec34c4cSmrg	intended->height = (Dimension)*clip_height;
7867a84e134Smrg}
7877a84e134Smrg
7887a84e134Smrgstatic void
7897a84e134SmrgXawViewportResize(Widget widget)
7907a84e134Smrg{
7917a84e134Smrg    ComputeLayout(widget, True, True);
7927a84e134Smrg}
7937a84e134Smrg
7947a84e134Smrg/*ARGSUSED*/
7957a84e134Smrgstatic Boolean
7965ec34c4cSmrgLayout(FormWidget w, unsigned int width _X_UNUSED, unsigned int height _X_UNUSED, Bool force _X_UNUSED)
7977a84e134Smrg{
7987a84e134Smrg    ComputeLayout((Widget)w, True, True);
7997a84e134Smrg    w->form.preferred_width = XtWidth(w);
8007a84e134Smrg    w->form.preferred_height = XtHeight(w);
8017a84e134Smrg
8027a84e134Smrg    return (False);
8037a84e134Smrg}
8047a84e134Smrg
8057a84e134Smrgstatic void
8067a84e134SmrgScrollUpDownProc(Widget widget, XtPointer closure, XtPointer call_data)
8077a84e134Smrg{
8087a84e134Smrg    ViewportWidget w = (ViewportWidget)closure;
8097a84e134Smrg    Widget child = w->viewport.child;
8105ec34c4cSmrg    int pix = (int)(long)call_data;
8117a84e134Smrg    int x, y;
8127a84e134Smrg
8137a84e134Smrg    if (child == NULL)
8147a84e134Smrg	return;
8157a84e134Smrg
8167a84e134Smrg    x = XtX(child) - (widget == w->viewport.horiz_bar ? pix : 0);
8177a84e134Smrg    y = XtY(child) - (widget == w->viewport.vert_bar ? pix : 0);
8187a84e134Smrg    MoveChild(w, x, y);
8197a84e134Smrg}
8207a84e134Smrg
8217a84e134Smrg/*ARGSUSED*/
8227a84e134Smrgstatic void
8237a84e134SmrgThumbProc(Widget widget, XtPointer closure, XtPointer call_data)
8247a84e134Smrg{
8257a84e134Smrg    ViewportWidget w = (ViewportWidget)closure;
8267a84e134Smrg    Widget child = w->viewport.child;
8277a84e134Smrg    float percent = *(float *)call_data;
8287a84e134Smrg    int x, y;
8297a84e134Smrg
8307a84e134Smrg    if (child == NULL)
8317a84e134Smrg	return;
8327a84e134Smrg
8337a84e134Smrg    if (widget == w->viewport.horiz_bar)
8345ec34c4cSmrg	x = (int)(-percent * XtWidth(child));
8357a84e134Smrg    else
8367a84e134Smrg	x = XtX(child);
8377a84e134Smrg
8387a84e134Smrg    if (widget == w->viewport.vert_bar)
8395ec34c4cSmrg	y = (int)(-percent * XtHeight(child));
8407a84e134Smrg    else
8417a84e134Smrg	y = XtY(child);
8427a84e134Smrg
8437a84e134Smrg    MoveChild(w, x, y);
8447a84e134Smrg}
8457a84e134Smrg
8467a84e134Smrgstatic XtGeometryResult
8477a84e134SmrgTestSmaller(ViewportWidget w, XtWidgetGeometry *request,
8487a84e134Smrg	    XtWidgetGeometry *reply_return)
8497a84e134Smrg{
8507a84e134Smrg    if (request->width < XtWidth(w) || request->height < XtHeight(w))
8517a84e134Smrg	return (XtMakeGeometryRequest((Widget)w, request, reply_return));
8527a84e134Smrg
8537a84e134Smrg    return (XtGeometryYes);
8547a84e134Smrg}
8557a84e134Smrg
8567a84e134Smrgstatic XtGeometryResult
8577a84e134SmrgGeometryRequestPlusScrollbar(ViewportWidget w, Bool horizontal,
8587a84e134Smrg			     XtWidgetGeometry *request,
8597a84e134Smrg			     XtWidgetGeometry *reply_return)
8607a84e134Smrg{
8617a84e134Smrg    Widget sb;
8627a84e134Smrg    XtWidgetGeometry plusScrollbars;
8637a84e134Smrg
8647a84e134Smrg    plusScrollbars = *request;
8657a84e134Smrg    if ((sb = w->viewport.horiz_bar) == NULL)
8667a84e134Smrg	sb = CreateScrollbar(w, horizontal);
8675ec34c4cSmrg    request->width = (Dimension)(request->width + XtWidth(sb));
8685ec34c4cSmrg    request->height = (Dimension)(request->height + XtHeight(sb));
8697a84e134Smrg    XtDestroyWidget(sb);
8707a84e134Smrg    return (XtMakeGeometryRequest((Widget)w, &plusScrollbars, reply_return));
8717a84e134Smrg}
8727a84e134Smrg
8737a84e134Smrg#define WidthChange()	(request->width != XtWidth(w))
8747a84e134Smrg#define HeightChange()	(request->height != XtHeight(w))
875421c997bSmrgstatic XtGeometryResult
8767a84e134SmrgQueryGeometry(ViewportWidget w, XtWidgetGeometry *request,
8777a84e134Smrg	      XtWidgetGeometry *reply_return)
878421c997bSmrg{
879421c997bSmrg    if (w->viewport.allowhoriz && w->viewport.allowvert)
8807a84e134Smrg	return (TestSmaller(w, request, reply_return));
8817a84e134Smrg
8827a84e134Smrg    else if (w->viewport.allowhoriz && !w->viewport.allowvert) {
8837a84e134Smrg	if (WidthChange() && !HeightChange())
8847a84e134Smrg	    return (TestSmaller(w, request, reply_return));
8857a84e134Smrg	else if (!WidthChange() && HeightChange())
8867a84e134Smrg	    return (XtMakeGeometryRequest((Widget)w, request, reply_return));
8877a84e134Smrg	else if (WidthChange() && HeightChange())
8887a84e134Smrg	    return (GeometryRequestPlusScrollbar(w, True, request, reply_return));
8897a84e134Smrg	else /* !WidthChange() && !HeightChange() */
8907a84e134Smrg	    return (XtGeometryYes);
8917a84e134Smrg    }
8927a84e134Smrg    else if (!w->viewport.allowhoriz && w->viewport.allowvert) {
8937a84e134Smrg	if (!WidthChange() && HeightChange())
8947a84e134Smrg	    return (TestSmaller(w, request, reply_return));
8957a84e134Smrg	else if (WidthChange() && !HeightChange())
8967a84e134Smrg	    return (XtMakeGeometryRequest((Widget)w, request, reply_return));
8977a84e134Smrg	else if (WidthChange() && HeightChange())
8987a84e134Smrg	    return (GeometryRequestPlusScrollbar(w, False, request, reply_return));
8997a84e134Smrg	else /* !WidthChange() && !HeightChange() */
9007a84e134Smrg	    return (XtGeometryYes);
9017a84e134Smrg    }
9027a84e134Smrg    else /* (!w->viewport.allowhoriz && !w->viewport.allowvert) */
9037a84e134Smrg	return (XtMakeGeometryRequest((Widget)w, request, reply_return));
9047a84e134Smrg}
9057a84e134Smrg#undef WidthChange
9067a84e134Smrg#undef HeightChange
9077a84e134Smrg
9087a84e134Smrgstatic XtGeometryResult
9097a84e134SmrgXawViewportGeometryManager(Widget child, XtWidgetGeometry *request,
9107a84e134Smrg			   XtWidgetGeometry *reply)
9117a84e134Smrg{
9127a84e134Smrg    ViewportWidget w = (ViewportWidget)child->core.parent;
9137a84e134Smrg    Bool rWidth = (request->request_mode & CWWidth) != 0;
9147a84e134Smrg    Bool rHeight = (request->request_mode & CWHeight) != 0;
9157a84e134Smrg    XtWidgetGeometry allowed;
9167a84e134Smrg    XtGeometryResult result;
9177a84e134Smrg    Bool reconfigured;
9187a84e134Smrg    Bool child_changed_size;
9197a84e134Smrg    unsigned int height_remaining;
9207a84e134Smrg
9217a84e134Smrg    if (request->request_mode & XtCWQueryOnly)
9227a84e134Smrg	return (QueryGeometry(w, request, reply));
9237a84e134Smrg
9247a84e134Smrg    if (child != w->viewport.child
9255ec34c4cSmrg	|| request->request_mode & (XtGeometryMask)(~(CWWidth | CWHeight | CWBorderWidth))
9267a84e134Smrg	|| ((request->request_mode & CWBorderWidth)
9277a84e134Smrg	    && request->border_width > 0))
9287a84e134Smrg	return (XtGeometryNo);
9297a84e134Smrg
9307a84e134Smrg    allowed = *request;
9317a84e134Smrg
9327a84e134Smrg    reconfigured = GetGeometry((Widget)w,
9337a84e134Smrg				rWidth ? request->width : XtWidth(w),
9347a84e134Smrg				rHeight ? request->height : XtHeight(w));
9357a84e134Smrg
9367a84e134Smrg    child_changed_size = (rWidth && XtWidth(child) != request->width) ||
9377a84e134Smrg			 (rHeight && XtHeight(child) != request->height);
9387a84e134Smrg
9397a84e134Smrg    height_remaining = XtHeight(w);
9407a84e134Smrg    if (rWidth && XtWidth(w) != request->width) {
9417a84e134Smrg	if (w->viewport.allowhoriz && request->width > XtWidth(w)) {
9427a84e134Smrg	    /* horizontal scrollbar will be needed so possibly reduce height */
943421c997bSmrg	    Widget bar;
9447a84e134Smrg
9457a84e134Smrg	    if ((bar = w->viewport.horiz_bar) == NULL)
9467a84e134Smrg		bar = CreateScrollbar(w, True);
9475ec34c4cSmrg	    height_remaining = (height_remaining - (unsigned)(XtHeight(bar) + XtBorderWidth(bar)));
9487a84e134Smrg	    reconfigured = True;
9497a84e134Smrg	}
9507a84e134Smrg	else
9517a84e134Smrg	    allowed.width = XtWidth(w);
9527a84e134Smrg    }
9537a84e134Smrg    if (rHeight && height_remaining != request->height) {
9547a84e134Smrg	if (w->viewport.allowvert && request->height > height_remaining) {
9557a84e134Smrg	    /* vertical scrollbar will be needed, so possibly reduce width */
9567a84e134Smrg	    if (!w->viewport.allowhoriz || request->width < XtWidth(w)) {
9577a84e134Smrg		Widget bar;
9587a84e134Smrg
9597a84e134Smrg		if ((bar = w->viewport.vert_bar) == NULL)
9607a84e134Smrg		    bar = CreateScrollbar(w, False);
9617a84e134Smrg		if (!rWidth) {
9627a84e134Smrg		    allowed.width = XtWidth(w);
9637a84e134Smrg		    allowed.request_mode |= CWWidth;
9647a84e134Smrg		}
9657a84e134Smrg		if (allowed.width  >  XtWidth(bar) + XtBorderWidth(bar))
9665ec34c4cSmrg		    allowed.width = (Dimension)(allowed.width - (XtWidth(bar) + XtBorderWidth(bar)));
9677a84e134Smrg		else
9687a84e134Smrg		    allowed.width = 1;
9697a84e134Smrg		reconfigured = True;
9707a84e134Smrg	    }
9717a84e134Smrg	}
9727a84e134Smrg	else
9735ec34c4cSmrg	    allowed.height = (Dimension)height_remaining;
9747a84e134Smrg    }
9757a84e134Smrg
9767a84e134Smrg    if (allowed.width != request->width || allowed.height != request->height) {
9777a84e134Smrg	*reply = allowed;
9787a84e134Smrg	result = XtGeometryAlmost;
9797a84e134Smrg    }
9807a84e134Smrg    else {
9817a84e134Smrg	if (rWidth)
9827a84e134Smrg	    XtWidth(child) = request->width;
9837a84e134Smrg	if (rHeight)
9847a84e134Smrg	    XtHeight(child) = request->height;
9857a84e134Smrg	result = XtGeometryYes;
9867a84e134Smrg    }
9877a84e134Smrg
9887a84e134Smrg    if (reconfigured || child_changed_size)
9897a84e134Smrg	ComputeLayout((Widget)w, False, result == XtGeometryYes);
9907a84e134Smrg
9917a84e134Smrg    return (result);
9927a84e134Smrg}
9937a84e134Smrg
9947a84e134Smrgstatic Bool
9957a84e134SmrgGetGeometry(Widget w, unsigned int width, unsigned int height)
9967a84e134Smrg{
9977a84e134Smrg    XtWidgetGeometry geometry, return_geom;
9987a84e134Smrg    XtGeometryResult result;
9997a84e134Smrg
10007a84e134Smrg    if (width == XtWidth(w) && height == XtHeight(w))
10017a84e134Smrg	return (False);
10027a84e134Smrg
10037a84e134Smrg    geometry.request_mode = CWWidth | CWHeight;
10045ec34c4cSmrg    geometry.width = (Dimension)width;
10055ec34c4cSmrg    geometry.height = (Dimension)height;
10067a84e134Smrg
10077a84e134Smrg    if (XtIsRealized(w)) {
10087a84e134Smrg	if (((ViewportWidget)w)->viewport.allowhoriz && width > XtWidth(w))
10097a84e134Smrg	    geometry.width = XtWidth(w);
10107a84e134Smrg	if (((ViewportWidget)w)->viewport.allowvert && height > XtHeight(w))
10117a84e134Smrg	    geometry.height = XtHeight(w);
10127a84e134Smrg    }
10137a84e134Smrg    else {
10147a84e134Smrg	/* This is the Realize call; we'll inherit a w&h iff none currently */
10157a84e134Smrg	if (XtWidth(w) != 0) {
10167a84e134Smrg	    if (XtHeight(w) != 0)
10177a84e134Smrg		return (False);
10187a84e134Smrg	    geometry.width = XtWidth(w);
10197a84e134Smrg	}
10207a84e134Smrg	if (XtHeight(w) != 0)
10217a84e134Smrg	    geometry.height = XtHeight(w);
10227a84e134Smrg    }
10237a84e134Smrg
10247a84e134Smrg    result = XtMakeGeometryRequest(w, &geometry, &return_geom);
10257a84e134Smrg    if (result == XtGeometryAlmost)
10267a84e134Smrg	result = XtMakeGeometryRequest(w, &return_geom, NULL);
10277a84e134Smrg
10287a84e134Smrg    return (result == XtGeometryYes);
10297a84e134Smrg}
10307a84e134Smrg
10317a84e134Smrgstatic XtGeometryResult
10327a84e134SmrgXawViewportQueryGeometry(Widget w, XtWidgetGeometry *constraints,
10337a84e134Smrg			 XtWidgetGeometry *reply)
10347a84e134Smrg{
10357a84e134Smrg    if (((ViewportWidget)w)->viewport.child != NULL)
10367a84e134Smrg	return (XtQueryGeometry(((ViewportWidget)w)->viewport.child,
10377a84e134Smrg				constraints, reply));
10387a84e134Smrg
10397a84e134Smrg    return (XtGeometryYes);
10407a84e134Smrg}
10417a84e134Smrg
10427a84e134Smrgvoid
10437a84e134SmrgXawViewportSetLocation
10447a84e134Smrg(
10457a84e134Smrg Widget gw,
10467a84e134Smrg#if NeedWidePrototypes
10477a84e134Smrg double xoff, double yoff
10487a84e134Smrg#else
10497a84e134Smrg float xoff, float yoff
10507a84e134Smrg#endif
10517a84e134Smrg )
10527a84e134Smrg{
10537a84e134Smrg    ViewportWidget w = (ViewportWidget)gw;
10547a84e134Smrg    Widget child = w->viewport.child;
10557a84e134Smrg    int x, y;
10567a84e134Smrg
10577a84e134Smrg    if (xoff > 1.0)			/* scroll to right */
10587a84e134Smrg	x = XtWidth(child);
1059421c997bSmrg    else if (xoff < 0.0)		/* if the offset is < 0.0 nothing */
10607a84e134Smrg	x = XtX(child);
10617a84e134Smrg    else
10625ec34c4cSmrg	x = (int)((float)XtWidth(child) * xoff);
10637a84e134Smrg
1064421c997bSmrg    if (yoff > 1.0)
10657a84e134Smrg	y = XtHeight(child);
10667a84e134Smrg    else if (yoff < 0.0)
10677a84e134Smrg	y = XtY(child);
10687a84e134Smrg    else
10695ec34c4cSmrg	y = (int)((float)XtHeight(child) * yoff);
10707a84e134Smrg
10717a84e134Smrg    MoveChild (w, -x, -y);
10727a84e134Smrg}
10737a84e134Smrg
10747a84e134Smrgvoid
10757a84e134SmrgXawViewportSetCoordinates(Widget gw,
10767a84e134Smrg#if NeedWidePrototypes
10777a84e134Smrg	int x, int y
10787a84e134Smrg#else
10797a84e134Smrg	Position x, Position y
10807a84e134Smrg#endif
10817a84e134Smrg)
10827a84e134Smrg{
10837a84e134Smrg    ViewportWidget w = (ViewportWidget)gw;
10847a84e134Smrg    Widget child = w->viewport.child;
10857a84e134Smrg
10867a84e134Smrg    if (x > XtWidth(child))
10875ec34c4cSmrg	x = (Position)XtWidth(child);
10887a84e134Smrg    else if (x < 0)
10895ec34c4cSmrg	x = (Position)XtX(child);
10907a84e134Smrg
10917a84e134Smrg    if (y > XtHeight(child))
10925ec34c4cSmrg	y = (Position)XtHeight(child);
10937a84e134Smrg    else if (y < 0)
10945ec34c4cSmrg	y = (Position)XtY(child);
10957a84e134Smrg
10967a84e134Smrg    MoveChild (w, -x, -y);
10977a84e134Smrg}
1098