Viewport.c revision 421c997b
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 */
2197a84e134Smrg  },
2207a84e134Smrg  /* viewport */
2217a84e134Smrg  {
2227a84e134Smrg    NULL,				/* extension */
2237a84e134Smrg  },
2247a84e134Smrg};
2257a84e134Smrg
2267a84e134SmrgWidgetClass viewportWidgetClass = (WidgetClass)&viewportClassRec;
2277a84e134Smrg
2287a84e134Smrg/*
2297a84e134Smrg * Implementation
2307a84e134Smrg */
2317a84e134Smrgstatic Widget
2327a84e134SmrgCreateScrollbar(ViewportWidget w, Bool horizontal)
2337a84e134Smrg{
2347a84e134Smrg    static Arg barArgs[] = {
2357a84e134Smrg	{XtNorientation,	    0},
2367a84e134Smrg	{XtNlength,		    0},
2377a84e134Smrg	{XtNleft,		    0},
2387a84e134Smrg	{XtNright,		    0},
2397a84e134Smrg	{XtNtop,		    0},
2407a84e134Smrg	{XtNbottom,		    0},
2417a84e134Smrg	{XtNmappedWhenManaged,	    False},
2427a84e134Smrg    };
2437a84e134Smrg    Widget clip = w->viewport.clip;
2447a84e134Smrg    ViewportConstraints constraints =
2457a84e134Smrg	(ViewportConstraints)clip->core.constraints;
2467a84e134Smrg    Widget bar;
2477a84e134Smrg
2487a84e134Smrg    XtSetArg(barArgs[0], XtNorientation,
2497a84e134Smrg	   horizontal ? XtorientHorizontal : XtorientVertical);
2507a84e134Smrg    XtSetArg(barArgs[1], XtNlength,
2517a84e134Smrg	   horizontal ? XtWidth(clip) : XtHeight(clip));
2527a84e134Smrg    XtSetArg(barArgs[2], XtNleft,
2537a84e134Smrg	   !horizontal && w->viewport.useright ? XtChainRight : XtChainLeft);
2547a84e134Smrg    XtSetArg(barArgs[3], XtNright,
2557a84e134Smrg	   !horizontal && !w->viewport.useright ? XtChainLeft : XtChainRight);
2567a84e134Smrg    XtSetArg(barArgs[4], XtNtop,
2577a84e134Smrg	   horizontal && w->viewport.usebottom ? XtChainBottom: XtChainTop);
2587a84e134Smrg    XtSetArg(barArgs[5], XtNbottom,
2597a84e134Smrg	   horizontal && !w->viewport.usebottom ? XtChainTop: XtChainBottom);
2607a84e134Smrg
2617a84e134Smrg    bar = XtCreateWidget(horizontal ? "horizontal" : "vertical",
2627a84e134Smrg			 scrollbarWidgetClass, (Widget)w,
2637a84e134Smrg			 barArgs, XtNumber(barArgs));
2647a84e134Smrg    XtAddCallback(bar, XtNscrollProc, ScrollUpDownProc, (XtPointer)w);
2657a84e134Smrg    XtAddCallback(bar, XtNjumpProc, ThumbProc, (XtPointer)w);
2667a84e134Smrg
2677a84e134Smrg    if (horizontal) {
2687a84e134Smrg	w->viewport.horiz_bar = bar;
2697a84e134Smrg	constraints->form.vert_base = bar;
2707a84e134Smrg    }
2717a84e134Smrg    else {
2727a84e134Smrg	w->viewport.vert_bar = bar;
2737a84e134Smrg	constraints->form.horiz_base = bar;
2747a84e134Smrg    }
2757a84e134Smrg
2767a84e134Smrg    XtManageChild(bar);
2777a84e134Smrg
2787a84e134Smrg    return (bar);
2797a84e134Smrg}
2807a84e134Smrg
2817a84e134Smrg/*ARGSUSED*/
2827a84e134Smrgstatic void
2837a84e134SmrgXawViewportInitialize(Widget request, Widget cnew,
2847a84e134Smrg		      ArgList args, Cardinal *num_args)
2857a84e134Smrg{
2867a84e134Smrg    ViewportWidget w = (ViewportWidget)cnew;
2877a84e134Smrg    static Arg clip_args[8];
2887a84e134Smrg    Cardinal arg_cnt;
2897a84e134Smrg    Widget h_bar, v_bar;
2907a84e134Smrg    Dimension clip_height, clip_width;
2917a84e134Smrg
2927a84e134Smrg    w->form.default_spacing = 0; /* Reset the default spacing to 0 pixels */
2937a84e134Smrg
2947a84e134Smrg    /*
2957a84e134Smrg     * Initialize all widget pointers to NULL
2967a84e134Smrg     */
2977a84e134Smrg    w->viewport.child = NULL;
2987a84e134Smrg    w->viewport.horiz_bar = w->viewport.vert_bar = NULL;
2997a84e134Smrg
3007a84e134Smrg    /*
3017a84e134Smrg     * Create Clip Widget
3027a84e134Smrg     */
3037a84e134Smrg    arg_cnt = 0;
3047a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNbackgroundPixmap, None);	arg_cnt++;
3057a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNborderWidth, 0);		arg_cnt++;
3067a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNleft, XtChainLeft);		arg_cnt++;
3077a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNright, XtChainRight);	arg_cnt++;
3087a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNtop, XtChainTop);		arg_cnt++;
3097a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNbottom, XtChainBottom);	arg_cnt++;
3107a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNwidth, XtWidth(w));		arg_cnt++;
3117a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNheight, XtHeight(w));	arg_cnt++;
3127a84e134Smrg
3137a84e134Smrg    w->viewport.clip = XtCreateManagedWidget("clip", widgetClass, cnew,
3147a84e134Smrg					     clip_args, arg_cnt);
3157a84e134Smrg
316421c997bSmrg    if (!w->viewport.forcebars)
3177a84e134Smrg	return;		 /* If we are not forcing the bars then we are done */
3187a84e134Smrg
319421c997bSmrg    if (w->viewport.allowhoriz)
3207a84e134Smrg	(void)CreateScrollbar(w, True);
321421c997bSmrg    if (w->viewport.allowvert)
3227a84e134Smrg	(void)CreateScrollbar(w, False);
3237a84e134Smrg
3247a84e134Smrg    h_bar = w->viewport.horiz_bar;
3257a84e134Smrg    v_bar = w->viewport.vert_bar;
3267a84e134Smrg
3277a84e134Smrg    /*
3287a84e134Smrg     * Set the clip widget to the correct height
3297a84e134Smrg     */
3307a84e134Smrg    clip_width = XtWidth(w);
3317a84e134Smrg    clip_height = XtHeight(w);
3327a84e134Smrg
3337a84e134Smrg    if (h_bar != NULL &&  XtWidth(w) > XtWidth(h_bar) + XtBorderWidth(h_bar))
3347a84e134Smrg	clip_width -= XtWidth(h_bar) + XtBorderWidth(h_bar);
3357a84e134Smrg
3367a84e134Smrg    if (v_bar != NULL && XtHeight(w) > XtHeight(v_bar) + XtBorderWidth(v_bar))
3377a84e134Smrg	clip_height -= XtHeight(v_bar) + XtBorderWidth(v_bar);
3387a84e134Smrg
3397a84e134Smrg    arg_cnt = 0;
3407a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNwidth, clip_width); arg_cnt++;
3417a84e134Smrg    XtSetArg(clip_args[arg_cnt], XtNheight, clip_height); arg_cnt++;
3427a84e134Smrg    XtSetValues(w->viewport.clip, clip_args, arg_cnt);
3437a84e134Smrg}
3447a84e134Smrg
3457a84e134Smrg/*ARGSUSED*/
3467a84e134Smrgstatic void
3477a84e134SmrgXawViewportConstraintInitialize(Widget request, Widget cnew,
3487a84e134Smrg				ArgList args, Cardinal *num_args)
3497a84e134Smrg{
3507a84e134Smrg    ((ViewportConstraints)cnew->core.constraints)->viewport.reparented = False;
3517a84e134Smrg}
3527a84e134Smrg
3537a84e134Smrgstatic void
3547a84e134SmrgXawViewportRealize(Widget widget, XtValueMask *value_mask,
3557a84e134Smrg		   XSetWindowAttributes *attributes)
3567a84e134Smrg{
3577a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
3587a84e134Smrg    Widget child = w->viewport.child;
3597a84e134Smrg    Widget clip = w->viewport.clip;
3607a84e134Smrg
3617a84e134Smrg    *value_mask |= CWBitGravity;
3627a84e134Smrg    attributes->bit_gravity = NorthWestGravity;
3637a84e134Smrg    (*Superclass->core_class.realize)(widget, value_mask, attributes);
3647a84e134Smrg
3657a84e134Smrg    (*w->core.widget_class->core_class.resize)(widget);	/* turn on bars */
3667a84e134Smrg
3677a84e134Smrg    if (child != NULL) {
3687a84e134Smrg	XtMoveWidget(child, 0, 0);
3697a84e134Smrg	XtRealizeWidget(clip);
3707a84e134Smrg	XtRealizeWidget(child);
3717a84e134Smrg	XReparentWindow(XtDisplay(w), XtWindow(child), XtWindow(clip), 0, 0);
3727a84e134Smrg	XtMapWidget(child);
3737a84e134Smrg    }
3747a84e134Smrg}
3757a84e134Smrg
3767a84e134Smrg/*ARGSUSED*/
3777a84e134Smrgstatic Boolean
3787a84e134SmrgXawViewportSetValues(Widget current, Widget request, Widget cnew,
3797a84e134Smrg		     ArgList args, Cardinal *num_args)
3807a84e134Smrg{
3817a84e134Smrg    ViewportWidget w = (ViewportWidget)cnew;
3827a84e134Smrg    ViewportWidget cw = (ViewportWidget)current;
3837a84e134Smrg
3847a84e134Smrg    if (w->viewport.forcebars != cw->viewport.forcebars
3857a84e134Smrg	|| w->viewport.allowvert != cw->viewport.allowvert
3867a84e134Smrg	|| w->viewport.allowhoriz != cw->viewport.allowhoriz
3877a84e134Smrg	|| w->viewport.useright != cw->viewport.useright
3887a84e134Smrg	|| w->viewport.usebottom != cw->viewport.usebottom)
3897a84e134Smrg	(*w->core.widget_class->core_class.resize)(cnew); /* Recompute layout */
3907a84e134Smrg
3917a84e134Smrg    return (False);
3927a84e134Smrg}
3937a84e134Smrg
3947a84e134Smrgstatic void
3957a84e134SmrgXawViewportChangeManaged(Widget widget)
3967a84e134Smrg{
3977a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
3987a84e134Smrg    int num_children = w->composite.num_children;
3997a84e134Smrg    Widget child, *childP;
4007a84e134Smrg    int i;
4017a84e134Smrg
4027a84e134Smrg    child = NULL;
4037a84e134Smrg    for (childP = w->composite.children,
4047a84e134Smrg	 i = 0; i < num_children;
4057a84e134Smrg	 childP++, i++) {
4067a84e134Smrg	if (XtIsManaged(*childP)
4077a84e134Smrg	    && *childP != w->viewport.clip
4087a84e134Smrg	    && *childP != w->viewport.horiz_bar
4097a84e134Smrg	    && *childP != w->viewport.vert_bar)	{
4107a84e134Smrg	    child = *childP;
4117a84e134Smrg	    break;
4127a84e134Smrg	}
4137a84e134Smrg    }
4147a84e134Smrg
4157a84e134Smrg    if (child != w->viewport.child) {
4167a84e134Smrg	w->viewport.child = child;
4177a84e134Smrg	if (child != NULL) {
4187a84e134Smrg	    XtResizeWidget(child, XtWidth(child), XtHeight(child), 0);
4197a84e134Smrg	    if (XtIsRealized(widget)) {
4207a84e134Smrg		ViewportConstraints constraints =
4217a84e134Smrg		    (ViewportConstraints)child->core.constraints;
4227a84e134Smrg		if (!XtIsRealized(child)) {
4237a84e134Smrg		    Window window = XtWindow(w);
4247a84e134Smrg
4257a84e134Smrg		    XtMoveWidget(child, 0, 0);
4267a84e134Smrg		    w->core.window = XtWindow(w->viewport.clip);
4277a84e134Smrg		    XtRealizeWidget(child);
4287a84e134Smrg		    w->core.window = window;
4297a84e134Smrg		    constraints->viewport.reparented = True;
4307a84e134Smrg		}
4317a84e134Smrg		else if (!constraints->viewport.reparented) {
4327a84e134Smrg		    XReparentWindow(XtDisplay(w), XtWindow(child),
4337a84e134Smrg				    XtWindow(w->viewport.clip), 0, 0);
4347a84e134Smrg		    constraints->viewport.reparented = True;
4357a84e134Smrg		    if (child->core.mapped_when_managed)
4367a84e134Smrg		    XtMapWidget(child);
4377a84e134Smrg		}
4387a84e134Smrg	    }
4397a84e134Smrg	    GetGeometry(widget, XtWidth(child), XtHeight(child));
4407a84e134Smrg	    (*((ViewportWidgetClass)w->core.widget_class)->form_class.layout)
4417a84e134Smrg	    ((FormWidget)w, XtWidth(w), XtHeight(w), True /* True? */);
4427a84e134Smrg	}
4437a84e134Smrg    }
4447a84e134Smrg
4457a84e134Smrg#ifdef notdef
4467a84e134Smrg    (*Superclass->composite_class.change_managed)(widget);
4477a84e134Smrg#endif
4487a84e134Smrg}
4497a84e134Smrg
4507a84e134Smrgstatic void
4517a84e134SmrgSetBar(Widget w, int top, unsigned int length, unsigned int total)
4527a84e134Smrg{
4537a84e134Smrg    XawScrollbarSetThumb(w, (float)top / (float)total,
4547a84e134Smrg			 (float)length / (float)total);
4557a84e134Smrg}
4567a84e134Smrg
4577a84e134Smrgstatic void
4587a84e134SmrgRedrawThumbs(ViewportWidget w)
4597a84e134Smrg{
4607a84e134Smrg    Widget child = w->viewport.child;
4617a84e134Smrg    Widget clip = w->viewport.clip;
4627a84e134Smrg
4637a84e134Smrg    if (w->viewport.horiz_bar != NULL)
4647a84e134Smrg	SetBar(w->viewport.horiz_bar, -(int)XtX(child),
4657a84e134Smrg	       XtWidth(clip), XtWidth(child));
4667a84e134Smrg
4677a84e134Smrg    if (w->viewport.vert_bar != NULL)
4687a84e134Smrg	SetBar(w->viewport.vert_bar, -(int)XtY(child),
4697a84e134Smrg	       XtHeight(clip), XtHeight(child));
4707a84e134Smrg}
4717a84e134Smrg
4727a84e134Smrgstatic void
4737a84e134SmrgSendReport(ViewportWidget w, unsigned int changed)
4747a84e134Smrg{
4757a84e134Smrg    XawPannerReport rep;
4767a84e134Smrg
4777a84e134Smrg    if (w->viewport.report_callbacks) {
4787a84e134Smrg	Widget child = w->viewport.child;
4797a84e134Smrg	Widget clip = w->viewport.clip;
4807a84e134Smrg
4817a84e134Smrg	rep.changed = changed;
4827a84e134Smrg	rep.slider_x = -XtX(child);	/* child is canvas */
4837a84e134Smrg	rep.slider_y = -XtY(child);	/* clip is slider */
4847a84e134Smrg	rep.slider_width = XtWidth(clip);
4857a84e134Smrg	rep.slider_height = XtHeight(clip);
4867a84e134Smrg	rep.canvas_width = XtWidth(child);
4877a84e134Smrg	rep.canvas_height = XtHeight(child);
4887a84e134Smrg	XtCallCallbackList((Widget)w, w->viewport.report_callbacks,
4897a84e134Smrg			   (XtPointer)&rep);
4907a84e134Smrg    }
4917a84e134Smrg}
4927a84e134Smrg
4937a84e134Smrgstatic void
4947a84e134SmrgMoveChild(ViewportWidget w, int x, int y)
4957a84e134Smrg{
4967a84e134Smrg    Widget child = w->viewport.child;
4977a84e134Smrg    Widget clip = w->viewport.clip;
4987a84e134Smrg
4997a84e134Smrg    /* make sure we never move past right/bottom borders */
5007a84e134Smrg    if (-x + (int)XtWidth(clip) > XtWidth(child))
5017a84e134Smrg	x = -(int)(XtWidth(child) - XtWidth(clip));
5027a84e134Smrg
5037a84e134Smrg    if (-y + (int)XtHeight(clip) > XtHeight(child))
5047a84e134Smrg	y = -(int)(XtHeight(child) - XtHeight(clip));
5057a84e134Smrg
5067a84e134Smrg    /* make sure we never move past left/top borders */
5077a84e134Smrg    if (x >= 0)
5087a84e134Smrg	x = 0;
5097a84e134Smrg    if (y >= 0)
5107a84e134Smrg	y = 0;
5117a84e134Smrg
5127a84e134Smrg    XtMoveWidget(child, x, y);
5137a84e134Smrg    SendReport(w, (XawPRSliderX | XawPRSliderY));
5147a84e134Smrg
5157a84e134Smrg    RedrawThumbs(w);
5167a84e134Smrg}
5177a84e134Smrg
5187a84e134Smrgstatic void
5197a84e134SmrgComputeLayout(Widget widget, Bool query, Bool destroy_scrollbars)
5207a84e134Smrg{
5217a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
5227a84e134Smrg    Widget child = w->viewport.child;
5237a84e134Smrg    Widget clip = w->viewport.clip;
5247a84e134Smrg    ViewportConstraints constraints =
5257a84e134Smrg	(ViewportConstraints)clip->core.constraints;
5267a84e134Smrg    Bool needshoriz, needsvert;
5277a84e134Smrg    int clip_width, clip_height;
5287a84e134Smrg    XtWidgetGeometry intended;
5297a84e134Smrg
5307a84e134Smrg    if (child == NULL)
5317a84e134Smrg	return;
5327a84e134Smrg
5337a84e134Smrg    clip_width = XtWidth(w);
5347a84e134Smrg    clip_height = XtHeight(w);
5357a84e134Smrg    intended.request_mode = CWBorderWidth;
5367a84e134Smrg    intended.border_width = 0;
5377a84e134Smrg
5387a84e134Smrg    if (w->viewport.forcebars) {
5397a84e134Smrg	needsvert = w->viewport.allowvert;
5407a84e134Smrg	needshoriz = w->viewport.allowhoriz;
541421c997bSmrg	ComputeWithForceBars(widget, query, &intended,
5427a84e134Smrg			     &clip_width, &clip_height);
5437a84e134Smrg    }
5447a84e134Smrg    else {
5457a84e134Smrg	Dimension prev_width, prev_height;
5467a84e134Smrg	XtGeometryMask prev_mode;
5477a84e134Smrg	XtWidgetGeometry preferred;
5487a84e134Smrg
5497a84e134Smrg	needshoriz = needsvert = False;
5507a84e134Smrg
5517a84e134Smrg	/*
5527a84e134Smrg	 * intended.{width,height} caches the eventual child dimensions,
5537a84e134Smrg	 * but we don't set the mode bits until after we decide that the
5547a84e134Smrg	 * child's preferences are not acceptable
5557a84e134Smrg	 */
556421c997bSmrg	if (!w->viewport.allowhoriz)
5577a84e134Smrg	    intended.request_mode |= CWWidth;
5587a84e134Smrg
5597a84e134Smrg	if (XtWidth(child) < clip_width)
5607a84e134Smrg	    intended.width = clip_width;
5617a84e134Smrg	else
5627a84e134Smrg	    intended.width = XtWidth(child);
5637a84e134Smrg
5647a84e134Smrg	if (XtHeight(child) < clip_height)
5657a84e134Smrg	    intended.height = clip_height;
5667a84e134Smrg	else
5677a84e134Smrg	    intended.height = XtHeight(child);
5687a84e134Smrg
569421c997bSmrg	if (!w->viewport.allowvert)
5707a84e134Smrg	    intended.request_mode |= CWHeight;
5717a84e134Smrg
5727a84e134Smrg	if (!query) {
5737a84e134Smrg	    preferred.width = XtWidth(child);
5747a84e134Smrg	    preferred.height = XtHeight(child);
5757a84e134Smrg	}
5767a84e134Smrg	do { /* while intended != prev  */
5777a84e134Smrg	    if (query) {
5787a84e134Smrg		(void)XtQueryGeometry(child, &intended, &preferred);
5797a84e134Smrg		if (!(preferred.request_mode & CWWidth))
5807a84e134Smrg		    preferred.width = intended.width;
5817a84e134Smrg		if (!(preferred.request_mode & CWHeight))
5827a84e134Smrg		    preferred.height = intended.height;
5837a84e134Smrg	    }
5847a84e134Smrg	    prev_width = intended.width;
5857a84e134Smrg	    prev_height = intended.height;
5867a84e134Smrg	    prev_mode = intended.request_mode;
5877a84e134Smrg	    /*
5887a84e134Smrg	     * note that having once decided to turn on either bar
5897a84e134Smrg	     * we'll not change our mind until we're next resized,
5907a84e134Smrg	     * thus avoiding potential oscillations
5917a84e134Smrg	     */
5927a84e134Smrg#define CheckHoriz() \
5937a84e134Smrg	    if (w->viewport.allowhoriz &&				\
5947a84e134Smrg		preferred.width > clip_width) {				\
5957a84e134Smrg		if (!needshoriz) {					\
5967a84e134Smrg		    Widget bar;						\
5977a84e134Smrg									\
5987a84e134Smrg		    needshoriz = True;					\
5997a84e134Smrg		    if ((bar = w->viewport.horiz_bar) == NULL)		\
6007a84e134Smrg			bar = CreateScrollbar(w, True);			\
6017a84e134Smrg		    clip_height -= XtHeight(bar) + XtBorderWidth(bar);	\
6027a84e134Smrg		    if (clip_height < 1)				\
6037a84e134Smrg			clip_height = 1;				\
6047a84e134Smrg		}							\
6057a84e134Smrg		intended.width = preferred.width;			\
6067a84e134Smrg	    }
6077a84e134Smrg
6087a84e134Smrg	    CheckHoriz();
6097a84e134Smrg	    if (w->viewport.allowvert && preferred.height > clip_height) {
6107a84e134Smrg		if (!needsvert) {
6117a84e134Smrg		    Widget bar;
6127a84e134Smrg		    needsvert = True;
6137a84e134Smrg		    if ((bar = w->viewport.vert_bar) == NULL)
6147a84e134Smrg			bar = CreateScrollbar(w, False);
6157a84e134Smrg		    clip_width -= XtWidth(bar) + XtBorderWidth(bar);
6167a84e134Smrg		    if (clip_width < 1)
6177a84e134Smrg			clip_width = 1;
6187a84e134Smrg		    CheckHoriz();
6197a84e134Smrg		}
6207a84e134Smrg		intended.height = preferred.height;
6217a84e134Smrg	    }
6227a84e134Smrg	    if (!w->viewport.allowhoriz || preferred.width < clip_width) {
6237a84e134Smrg		intended.width = clip_width;
6247a84e134Smrg		intended.request_mode |= CWWidth;
6257a84e134Smrg	    }
6267a84e134Smrg	    if (!w->viewport.allowvert || preferred.height < clip_height) {
6277a84e134Smrg		intended.height = clip_height;
6287a84e134Smrg		intended.request_mode |= CWHeight;
6297a84e134Smrg	    }
6307a84e134Smrg	} while (intended.request_mode != prev_mode
6317a84e134Smrg		 || (intended.request_mode & CWWidth
6327a84e134Smrg		     && intended.width != prev_width)
6337a84e134Smrg		 || (intended.request_mode & CWHeight
6347a84e134Smrg		     && intended.height != prev_height));
6357a84e134Smrg    }
6367a84e134Smrg
6377a84e134Smrg    if (XtIsRealized(clip))
6387a84e134Smrg	XRaiseWindow(XtDisplay(clip), XtWindow(clip));
6397a84e134Smrg
6407a84e134Smrg    XtMoveWidget(clip,
6417a84e134Smrg		 needsvert ? w->viewport.useright ? 0 :
6427a84e134Smrg		 XtWidth(w->viewport.vert_bar)
6437a84e134Smrg		 + XtBorderWidth(w->viewport.vert_bar) : 0,
6447a84e134Smrg		 needshoriz ? w->viewport.usebottom ? 0 :
6457a84e134Smrg		 XtHeight(w->viewport.horiz_bar)
6467a84e134Smrg		 + XtBorderWidth(w->viewport.horiz_bar) : 0);
6477a84e134Smrg    XtResizeWidget(clip, clip_width, clip_height, 0);
648421c997bSmrg
6497a84e134Smrg    if (w->viewport.horiz_bar != NULL) {
6507a84e134Smrg	Widget bar = w->viewport.horiz_bar;
6517a84e134Smrg
6527a84e134Smrg	if (!needshoriz) {
6537a84e134Smrg	    constraints->form.vert_base = NULL;
6547a84e134Smrg	    if (destroy_scrollbars) {
6557a84e134Smrg		XtDestroyWidget(bar);
6567a84e134Smrg		w->viewport.horiz_bar = NULL;
6577a84e134Smrg	    }
6587a84e134Smrg	}
6597a84e134Smrg	else {
6607a84e134Smrg	    int bw = XtBorderWidth(bar);
6617a84e134Smrg
6627a84e134Smrg	    XtResizeWidget(bar, clip_width, XtHeight(bar), bw);
6637a84e134Smrg	    XtMoveWidget(bar,
6647a84e134Smrg			 needsvert && !w->viewport.useright
6657a84e134Smrg			 ? XtWidth(w->viewport.vert_bar) : -bw,
6667a84e134Smrg			 w->viewport.usebottom
6677a84e134Smrg			 ? XtHeight(w) - XtHeight(bar) - bw : -bw);
6687a84e134Smrg	    XtSetMappedWhenManaged(bar, True);
6697a84e134Smrg	}
6707a84e134Smrg    }
6717a84e134Smrg
6727a84e134Smrg    if (w->viewport.vert_bar != NULL) {
6737a84e134Smrg	Widget bar = w->viewport.vert_bar;
6747a84e134Smrg
6757a84e134Smrg	if (!needsvert)	{
6767a84e134Smrg	    constraints->form.horiz_base = NULL;
6777a84e134Smrg	    if (destroy_scrollbars) {
6787a84e134Smrg		XtDestroyWidget(bar);
6797a84e134Smrg		w->viewport.vert_bar = NULL;
6807a84e134Smrg	    }
6817a84e134Smrg	}
6827a84e134Smrg	else {
6837a84e134Smrg	    int bw = bar->core.border_width;
6847a84e134Smrg
6857a84e134Smrg	    XtResizeWidget(bar, XtWidth(bar), clip_height, bw);
6867a84e134Smrg	    XtMoveWidget(bar,
6877a84e134Smrg			w->viewport.useright
6887a84e134Smrg			? XtWidth(w) - XtWidth(bar) - bw : -bw,
6897a84e134Smrg			needshoriz && !w->viewport.usebottom
6907a84e134Smrg			? XtHeight(w->viewport.horiz_bar) : -bw);
6917a84e134Smrg	   XtSetMappedWhenManaged(bar, True);
6927a84e134Smrg	}
6937a84e134Smrg    }
6947a84e134Smrg
6957a84e134Smrg    if (child != NULL) {
6967a84e134Smrg	XtResizeWidget(child, intended.width, intended.height, 0);
6977a84e134Smrg	MoveChild(w, needshoriz ? XtX(child) : 0,	needsvert ? XtY(child) : 0);
6987a84e134Smrg    }
6997a84e134Smrg
7007a84e134Smrg    SendReport (w, XawPRAll);
7017a84e134Smrg}
7027a84e134Smrg
7037a84e134Smrg/*
7047a84e134Smrg * Function:
7057a84e134Smrg *	ComputeWithForceBars
7067a84e134Smrg *
7077a84e134Smrg * Parameters:
7087a84e134Smrg *	widget	    - viewport widget
7097a84e134Smrg *	query	    - whether or not to query the child
7107a84e134Smrg *	intended    - cache of the childs height is stored here
7117a84e134Smrg *		      (used and returned)
7127a84e134Smrg *	clip_width  - size of clip window (used and returned)
7137a84e134Smrg *	clip_height - ""
7147a84e134Smrg *
7157a84e134Smrg * Description:
7167a84e134Smrg *	Computes the layout give forcebars is set.
7177a84e134Smrg */
7187a84e134Smrgstatic void
7197a84e134SmrgComputeWithForceBars(Widget widget, Bool query, XtWidgetGeometry *intended,
7207a84e134Smrg		     int *clip_width, int *clip_height)
7217a84e134Smrg{
7227a84e134Smrg    ViewportWidget w = (ViewportWidget)widget;
7237a84e134Smrg    Widget child = w->viewport.child;
7247a84e134Smrg    XtWidgetGeometry preferred;
7257a84e134Smrg
7267a84e134Smrg    /*
7277a84e134Smrg     * If forcebars then needs = allows = has
7287a84e134Smrg     * Thus if needsvert is set it MUST have a scrollbar
7297a84e134Smrg     */
7307a84e134Smrg    if (w->viewport.allowvert) {
731421c997bSmrg	if (w->viewport.vert_bar == NULL)
7327a84e134Smrg	    w->viewport.vert_bar = CreateScrollbar(w, False);
7337a84e134Smrg
7347a84e134Smrg	*clip_width -= XtWidth(w->viewport.vert_bar) +
7357a84e134Smrg		       XtBorderWidth(w->viewport.vert_bar);
7367a84e134Smrg    }
7377a84e134Smrg
7387a84e134Smrg    if (w->viewport.allowhoriz) {
739421c997bSmrg	if (w->viewport.horiz_bar == NULL)
7407a84e134Smrg	    w->viewport.horiz_bar = CreateScrollbar(w, True);
7417a84e134Smrg
7427a84e134Smrg	*clip_height -= XtHeight(w->viewport.horiz_bar) +
7437a84e134Smrg			XtBorderWidth(w->viewport.horiz_bar);
7447a84e134Smrg    }
7457a84e134Smrg
7467a84e134Smrg    AssignMax(*clip_width, 1);
7477a84e134Smrg    AssignMax(*clip_height, 1);
7487a84e134Smrg
7497a84e134Smrg    if (!w->viewport.allowvert) {
7507a84e134Smrg	intended->height = *clip_height;
7517a84e134Smrg	intended->request_mode = CWHeight;
7527a84e134Smrg    }
7537a84e134Smrg    if (!w->viewport.allowhoriz) {
7547a84e134Smrg	intended->width = *clip_width;
7557a84e134Smrg	intended->request_mode = CWWidth;
7567a84e134Smrg    }
7577a84e134Smrg
7587a84e134Smrg    if (query) {
7597a84e134Smrg	if (w->viewport.allowvert || w->viewport.allowhoriz) {
7607a84e134Smrg	    XtQueryGeometry(child, intended, &preferred);
761421c997bSmrg
7627a84e134Smrg	    if (!(intended->request_mode & CWWidth)) {
7637a84e134Smrg		if (preferred.request_mode & CWWidth)
7647a84e134Smrg		    intended->width = preferred.width;
7657a84e134Smrg		else
7667a84e134Smrg		    intended->width = XtWidth(child);
7677a84e134Smrg	    }
7687a84e134Smrg
7697a84e134Smrg	    if (!(intended->request_mode & CWHeight)) {
7707a84e134Smrg		if (preferred.request_mode & CWHeight)
7717a84e134Smrg		    intended->height = preferred.height;
7727a84e134Smrg		else
7737a84e134Smrg		    intended->height = XtHeight(child);
7747a84e134Smrg	    }
7757a84e134Smrg	}
7767a84e134Smrg    }
7777a84e134Smrg    else {
7787a84e134Smrg	if (w->viewport.allowvert)
7797a84e134Smrg	    intended->height = XtHeight(child);
7807a84e134Smrg	if (w->viewport.allowhoriz)
7817a84e134Smrg	    intended->width = XtWidth(child);
7827a84e134Smrg    }
7837a84e134Smrg
7847a84e134Smrg    if (*clip_width > (int)intended->width)
7857a84e134Smrg	intended->width = *clip_width;
7867a84e134Smrg    if (*clip_height > (int)intended->height)
7877a84e134Smrg	intended->height = *clip_height;
7887a84e134Smrg}
7897a84e134Smrg
7907a84e134Smrgstatic void
7917a84e134SmrgXawViewportResize(Widget widget)
7927a84e134Smrg{
7937a84e134Smrg    ComputeLayout(widget, True, True);
7947a84e134Smrg}
7957a84e134Smrg
7967a84e134Smrg/*ARGSUSED*/
7977a84e134Smrgstatic Boolean
7987a84e134SmrgLayout(FormWidget w, unsigned int width, unsigned int height, Bool force)
7997a84e134Smrg{
8007a84e134Smrg    ComputeLayout((Widget)w, True, True);
8017a84e134Smrg    w->form.preferred_width = XtWidth(w);
8027a84e134Smrg    w->form.preferred_height = XtHeight(w);
8037a84e134Smrg
8047a84e134Smrg    return (False);
8057a84e134Smrg}
8067a84e134Smrg
8077a84e134Smrgstatic void
8087a84e134SmrgScrollUpDownProc(Widget widget, XtPointer closure, XtPointer call_data)
8097a84e134Smrg{
8107a84e134Smrg    ViewportWidget w = (ViewportWidget)closure;
8117a84e134Smrg    Widget child = w->viewport.child;
8127a84e134Smrg    int pix = (long)call_data;
8137a84e134Smrg    int x, y;
8147a84e134Smrg
8157a84e134Smrg    if (child == NULL)
8167a84e134Smrg	return;
8177a84e134Smrg
8187a84e134Smrg    x = XtX(child) - (widget == w->viewport.horiz_bar ? pix : 0);
8197a84e134Smrg    y = XtY(child) - (widget == w->viewport.vert_bar ? pix : 0);
8207a84e134Smrg    MoveChild(w, x, y);
8217a84e134Smrg}
8227a84e134Smrg
8237a84e134Smrg/*ARGSUSED*/
8247a84e134Smrgstatic void
8257a84e134SmrgThumbProc(Widget widget, XtPointer closure, XtPointer call_data)
8267a84e134Smrg{
8277a84e134Smrg    ViewportWidget w = (ViewportWidget)closure;
8287a84e134Smrg    Widget child = w->viewport.child;
8297a84e134Smrg    float percent = *(float *)call_data;
8307a84e134Smrg    int x, y;
8317a84e134Smrg
8327a84e134Smrg    if (child == NULL)
8337a84e134Smrg	return;
8347a84e134Smrg
8357a84e134Smrg    if (widget == w->viewport.horiz_bar)
8367a84e134Smrg	x = -percent * XtWidth(child);
8377a84e134Smrg    else
8387a84e134Smrg	x = XtX(child);
8397a84e134Smrg
8407a84e134Smrg    if (widget == w->viewport.vert_bar)
8417a84e134Smrg	y = -percent * XtHeight(child);
8427a84e134Smrg    else
8437a84e134Smrg	y = XtY(child);
8447a84e134Smrg
8457a84e134Smrg    MoveChild(w, x, y);
8467a84e134Smrg}
8477a84e134Smrg
8487a84e134Smrgstatic XtGeometryResult
8497a84e134SmrgTestSmaller(ViewportWidget w, XtWidgetGeometry *request,
8507a84e134Smrg	    XtWidgetGeometry *reply_return)
8517a84e134Smrg{
8527a84e134Smrg    if (request->width < XtWidth(w) || request->height < XtHeight(w))
8537a84e134Smrg	return (XtMakeGeometryRequest((Widget)w, request, reply_return));
8547a84e134Smrg
8557a84e134Smrg    return (XtGeometryYes);
8567a84e134Smrg}
8577a84e134Smrg
8587a84e134Smrgstatic XtGeometryResult
8597a84e134SmrgGeometryRequestPlusScrollbar(ViewportWidget w, Bool horizontal,
8607a84e134Smrg			     XtWidgetGeometry *request,
8617a84e134Smrg			     XtWidgetGeometry *reply_return)
8627a84e134Smrg{
8637a84e134Smrg    Widget sb;
8647a84e134Smrg    XtWidgetGeometry plusScrollbars;
8657a84e134Smrg
8667a84e134Smrg    plusScrollbars = *request;
8677a84e134Smrg    if ((sb = w->viewport.horiz_bar) == NULL)
8687a84e134Smrg	sb = CreateScrollbar(w, horizontal);
8697a84e134Smrg    request->width += XtWidth(sb);
8707a84e134Smrg    request->height += XtHeight(sb);
8717a84e134Smrg    XtDestroyWidget(sb);
8727a84e134Smrg    return (XtMakeGeometryRequest((Widget)w, &plusScrollbars, reply_return));
8737a84e134Smrg}
8747a84e134Smrg
8757a84e134Smrg#define WidthChange()	(request->width != XtWidth(w))
8767a84e134Smrg#define HeightChange()	(request->height != XtHeight(w))
877421c997bSmrgstatic XtGeometryResult
8787a84e134SmrgQueryGeometry(ViewportWidget w, XtWidgetGeometry *request,
8797a84e134Smrg	      XtWidgetGeometry *reply_return)
880421c997bSmrg{
881421c997bSmrg    if (w->viewport.allowhoriz && w->viewport.allowvert)
8827a84e134Smrg	return (TestSmaller(w, request, reply_return));
8837a84e134Smrg
8847a84e134Smrg    else if (w->viewport.allowhoriz && !w->viewport.allowvert) {
8857a84e134Smrg	if (WidthChange() && !HeightChange())
8867a84e134Smrg	    return (TestSmaller(w, request, reply_return));
8877a84e134Smrg	else if (!WidthChange() && HeightChange())
8887a84e134Smrg	    return (XtMakeGeometryRequest((Widget)w, request, reply_return));
8897a84e134Smrg	else if (WidthChange() && HeightChange())
8907a84e134Smrg	    return (GeometryRequestPlusScrollbar(w, True, request, reply_return));
8917a84e134Smrg	else /* !WidthChange() && !HeightChange() */
8927a84e134Smrg	    return (XtGeometryYes);
8937a84e134Smrg    }
8947a84e134Smrg    else if (!w->viewport.allowhoriz && w->viewport.allowvert) {
8957a84e134Smrg	if (!WidthChange() && HeightChange())
8967a84e134Smrg	    return (TestSmaller(w, request, reply_return));
8977a84e134Smrg	else if (WidthChange() && !HeightChange())
8987a84e134Smrg	    return (XtMakeGeometryRequest((Widget)w, request, reply_return));
8997a84e134Smrg	else if (WidthChange() && HeightChange())
9007a84e134Smrg	    return (GeometryRequestPlusScrollbar(w, False, request, reply_return));
9017a84e134Smrg	else /* !WidthChange() && !HeightChange() */
9027a84e134Smrg	    return (XtGeometryYes);
9037a84e134Smrg    }
9047a84e134Smrg    else /* (!w->viewport.allowhoriz && !w->viewport.allowvert) */
9057a84e134Smrg	return (XtMakeGeometryRequest((Widget)w, request, reply_return));
9067a84e134Smrg}
9077a84e134Smrg#undef WidthChange
9087a84e134Smrg#undef HeightChange
9097a84e134Smrg
9107a84e134Smrgstatic XtGeometryResult
9117a84e134SmrgXawViewportGeometryManager(Widget child, XtWidgetGeometry *request,
9127a84e134Smrg			   XtWidgetGeometry *reply)
9137a84e134Smrg{
9147a84e134Smrg    ViewportWidget w = (ViewportWidget)child->core.parent;
9157a84e134Smrg    Bool rWidth = (request->request_mode & CWWidth) != 0;
9167a84e134Smrg    Bool rHeight = (request->request_mode & CWHeight) != 0;
9177a84e134Smrg    XtWidgetGeometry allowed;
9187a84e134Smrg    XtGeometryResult result;
9197a84e134Smrg    Bool reconfigured;
9207a84e134Smrg    Bool child_changed_size;
9217a84e134Smrg    unsigned int height_remaining;
9227a84e134Smrg
9237a84e134Smrg    if (request->request_mode & XtCWQueryOnly)
9247a84e134Smrg	return (QueryGeometry(w, request, reply));
9257a84e134Smrg
9267a84e134Smrg    if (child != w->viewport.child
9277a84e134Smrg	|| request->request_mode & ~(CWWidth | CWHeight | CWBorderWidth)
9287a84e134Smrg	|| ((request->request_mode & CWBorderWidth)
9297a84e134Smrg	    && request->border_width > 0))
9307a84e134Smrg	return (XtGeometryNo);
9317a84e134Smrg
9327a84e134Smrg    allowed = *request;
9337a84e134Smrg
9347a84e134Smrg    reconfigured = GetGeometry((Widget)w,
9357a84e134Smrg				rWidth ? request->width : XtWidth(w),
9367a84e134Smrg				rHeight ? request->height : XtHeight(w));
9377a84e134Smrg
9387a84e134Smrg    child_changed_size = (rWidth && XtWidth(child) != request->width) ||
9397a84e134Smrg			 (rHeight && XtHeight(child) != request->height);
9407a84e134Smrg
9417a84e134Smrg    height_remaining = XtHeight(w);
9427a84e134Smrg    if (rWidth && XtWidth(w) != request->width) {
9437a84e134Smrg	if (w->viewport.allowhoriz && request->width > XtWidth(w)) {
9447a84e134Smrg	    /* horizontal scrollbar will be needed so possibly reduce height */
945421c997bSmrg	    Widget bar;
9467a84e134Smrg
9477a84e134Smrg	    if ((bar = w->viewport.horiz_bar) == NULL)
9487a84e134Smrg		bar = CreateScrollbar(w, True);
9497a84e134Smrg	    height_remaining -= XtHeight(bar) + XtBorderWidth(bar);
9507a84e134Smrg	    reconfigured = True;
9517a84e134Smrg	}
9527a84e134Smrg	else
9537a84e134Smrg	    allowed.width = XtWidth(w);
9547a84e134Smrg    }
9557a84e134Smrg    if (rHeight && height_remaining != request->height) {
9567a84e134Smrg	if (w->viewport.allowvert && request->height > height_remaining) {
9577a84e134Smrg	    /* vertical scrollbar will be needed, so possibly reduce width */
9587a84e134Smrg	    if (!w->viewport.allowhoriz || request->width < XtWidth(w)) {
9597a84e134Smrg		Widget bar;
9607a84e134Smrg
9617a84e134Smrg		if ((bar = w->viewport.vert_bar) == NULL)
9627a84e134Smrg		    bar = CreateScrollbar(w, False);
9637a84e134Smrg		if (!rWidth) {
9647a84e134Smrg		    allowed.width = XtWidth(w);
9657a84e134Smrg		    allowed.request_mode |= CWWidth;
9667a84e134Smrg		}
9677a84e134Smrg		if (allowed.width  >  XtWidth(bar) + XtBorderWidth(bar))
9687a84e134Smrg		    allowed.width -= XtWidth(bar) + XtBorderWidth(bar);
9697a84e134Smrg		else
9707a84e134Smrg		    allowed.width = 1;
9717a84e134Smrg		reconfigured = True;
9727a84e134Smrg	    }
9737a84e134Smrg	}
9747a84e134Smrg	else
9757a84e134Smrg	    allowed.height = height_remaining;
9767a84e134Smrg    }
9777a84e134Smrg
9787a84e134Smrg    if (allowed.width != request->width || allowed.height != request->height) {
9797a84e134Smrg	*reply = allowed;
9807a84e134Smrg	result = XtGeometryAlmost;
9817a84e134Smrg    }
9827a84e134Smrg    else {
9837a84e134Smrg	if (rWidth)
9847a84e134Smrg	    XtWidth(child) = request->width;
9857a84e134Smrg	if (rHeight)
9867a84e134Smrg	    XtHeight(child) = request->height;
9877a84e134Smrg	result = XtGeometryYes;
9887a84e134Smrg    }
9897a84e134Smrg
9907a84e134Smrg    if (reconfigured || child_changed_size)
9917a84e134Smrg	ComputeLayout((Widget)w, False, result == XtGeometryYes);
9927a84e134Smrg
9937a84e134Smrg    return (result);
9947a84e134Smrg}
9957a84e134Smrg
9967a84e134Smrgstatic Bool
9977a84e134SmrgGetGeometry(Widget w, unsigned int width, unsigned int height)
9987a84e134Smrg{
9997a84e134Smrg    XtWidgetGeometry geometry, return_geom;
10007a84e134Smrg    XtGeometryResult result;
10017a84e134Smrg
10027a84e134Smrg    if (width == XtWidth(w) && height == XtHeight(w))
10037a84e134Smrg	return (False);
10047a84e134Smrg
10057a84e134Smrg    geometry.request_mode = CWWidth | CWHeight;
10067a84e134Smrg    geometry.width = width;
10077a84e134Smrg    geometry.height = height;
10087a84e134Smrg
10097a84e134Smrg    if (XtIsRealized(w)) {
10107a84e134Smrg	if (((ViewportWidget)w)->viewport.allowhoriz && width > XtWidth(w))
10117a84e134Smrg	    geometry.width = XtWidth(w);
10127a84e134Smrg	if (((ViewportWidget)w)->viewport.allowvert && height > XtHeight(w))
10137a84e134Smrg	    geometry.height = XtHeight(w);
10147a84e134Smrg    }
10157a84e134Smrg    else {
10167a84e134Smrg	/* This is the Realize call; we'll inherit a w&h iff none currently */
10177a84e134Smrg	if (XtWidth(w) != 0) {
10187a84e134Smrg	    if (XtHeight(w) != 0)
10197a84e134Smrg		return (False);
10207a84e134Smrg	    geometry.width = XtWidth(w);
10217a84e134Smrg	}
10227a84e134Smrg	if (XtHeight(w) != 0)
10237a84e134Smrg	    geometry.height = XtHeight(w);
10247a84e134Smrg    }
10257a84e134Smrg
10267a84e134Smrg    result = XtMakeGeometryRequest(w, &geometry, &return_geom);
10277a84e134Smrg    if (result == XtGeometryAlmost)
10287a84e134Smrg	result = XtMakeGeometryRequest(w, &return_geom, NULL);
10297a84e134Smrg
10307a84e134Smrg    return (result == XtGeometryYes);
10317a84e134Smrg}
10327a84e134Smrg
10337a84e134Smrgstatic XtGeometryResult
10347a84e134SmrgXawViewportQueryGeometry(Widget w, XtWidgetGeometry *constraints,
10357a84e134Smrg			 XtWidgetGeometry *reply)
10367a84e134Smrg{
10377a84e134Smrg    if (((ViewportWidget)w)->viewport.child != NULL)
10387a84e134Smrg	return (XtQueryGeometry(((ViewportWidget)w)->viewport.child,
10397a84e134Smrg				constraints, reply));
10407a84e134Smrg
10417a84e134Smrg    return (XtGeometryYes);
10427a84e134Smrg}
10437a84e134Smrg
10447a84e134Smrgvoid
10457a84e134SmrgXawViewportSetLocation
10467a84e134Smrg(
10477a84e134Smrg Widget gw,
10487a84e134Smrg#if NeedWidePrototypes
10497a84e134Smrg double xoff, double yoff
10507a84e134Smrg#else
10517a84e134Smrg float xoff, float yoff
10527a84e134Smrg#endif
10537a84e134Smrg )
10547a84e134Smrg{
10557a84e134Smrg    ViewportWidget w = (ViewportWidget)gw;
10567a84e134Smrg    Widget child = w->viewport.child;
10577a84e134Smrg    int x, y;
10587a84e134Smrg
10597a84e134Smrg    if (xoff > 1.0)			/* scroll to right */
10607a84e134Smrg	x = XtWidth(child);
1061421c997bSmrg    else if (xoff < 0.0)		/* if the offset is < 0.0 nothing */
10627a84e134Smrg	x = XtX(child);
10637a84e134Smrg    else
10647a84e134Smrg	x = (float)XtWidth(child) * xoff;
10657a84e134Smrg
1066421c997bSmrg    if (yoff > 1.0)
10677a84e134Smrg	y = XtHeight(child);
10687a84e134Smrg    else if (yoff < 0.0)
10697a84e134Smrg	y = XtY(child);
10707a84e134Smrg    else
10717a84e134Smrg	y = (float)XtHeight(child) * yoff;
10727a84e134Smrg
10737a84e134Smrg    MoveChild (w, -x, -y);
10747a84e134Smrg}
10757a84e134Smrg
10767a84e134Smrgvoid
10777a84e134SmrgXawViewportSetCoordinates(Widget gw,
10787a84e134Smrg#if NeedWidePrototypes
10797a84e134Smrg	int x, int y
10807a84e134Smrg#else
10817a84e134Smrg	Position x, Position y
10827a84e134Smrg#endif
10837a84e134Smrg)
10847a84e134Smrg{
10857a84e134Smrg    ViewportWidget w = (ViewportWidget)gw;
10867a84e134Smrg    Widget child = w->viewport.child;
10877a84e134Smrg
10887a84e134Smrg    if (x > XtWidth(child))
10897a84e134Smrg	x = XtWidth(child);
10907a84e134Smrg    else if (x < 0)
10917a84e134Smrg	x = XtX(child);
10927a84e134Smrg
10937a84e134Smrg    if (y > XtHeight(child))
10947a84e134Smrg	y = XtHeight(child);
10957a84e134Smrg    else if (y < 0)
10967a84e134Smrg	y = XtY(child);
10977a84e134Smrg
10987a84e134Smrg    MoveChild (w, -x, -y);
10997a84e134Smrg}
1100