upload tizen2.0 source
[framework/uifw/xorg/lib/libxaw.git] / src / Viewport.c
1 /***********************************************************
2
3 Copyright 1987, 1988, 1994, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
37
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
45
46 ******************************************************************/
47
48 #ifdef HAVE_CONFIG_H
49 #include <config.h>
50 #endif
51 #include <X11/IntrinsicP.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Xmu/Misc.h>
54 #include <X11/Xaw/Scrollbar.h>
55 #include <X11/Xaw/ViewportP.h>
56 #include <X11/Xaw/XawInit.h>
57 #include "Private.h"
58
59 /*
60  * Class Methods
61  */
62 static Boolean Layout(FormWidget, unsigned int, unsigned int, Bool);
63 static void XawViewportChangeManaged(Widget);
64 static void XawViewportInitialize(Widget, Widget, ArgList, Cardinal*);
65 static void
66 XawViewportConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
67 static XtGeometryResult XawViewportGeometryManager(Widget, XtWidgetGeometry*,
68                                                    XtWidgetGeometry*);
69 static XtGeometryResult XawViewportQueryGeometry(Widget,
70                                                  XtWidgetGeometry*,
71                                                  XtWidgetGeometry*);
72 static void XawViewportRealize(Widget, XtValueMask*, XSetWindowAttributes*);
73 static void XawViewportResize(Widget);
74 static Boolean XawViewportSetValues(Widget, Widget, Widget,
75                                     ArgList, Cardinal*);
76
77 /*
78  * Prototypes
79  */
80 static void ComputeLayout(Widget, Bool, Bool);
81 static void ComputeWithForceBars(Widget, Bool, XtWidgetGeometry*,
82                                  int*, int*);
83 static Widget CreateScrollbar(ViewportWidget, Bool);
84 static XtGeometryResult GeometryRequestPlusScrollbar(ViewportWidget, Bool,
85                                                      XtWidgetGeometry*,
86                                                      XtWidgetGeometry*);
87 static Bool GetGeometry(Widget, unsigned int, unsigned int);
88 static void MoveChild(ViewportWidget, int, int);
89 static XtGeometryResult QueryGeometry(ViewportWidget, XtWidgetGeometry*,
90                                       XtWidgetGeometry*);
91 static void RedrawThumbs(ViewportWidget);
92 static void ScrollUpDownProc(Widget, XtPointer, XtPointer);
93 static void SendReport(ViewportWidget, unsigned int);
94 static void SetBar(Widget, int, unsigned int, unsigned int);
95 static XtGeometryResult TestSmaller(ViewportWidget, XtWidgetGeometry*,
96                                     XtWidgetGeometry*);
97 static void ThumbProc(Widget, XtPointer, XtPointer);
98
99 /*
100  * Initialization
101  */
102 #define offset(field) XtOffsetOf(ViewportRec, viewport.field)
103 static XtResource resources[] = {
104   {
105     XtNforceBars,
106     XtCBoolean,
107     XtRBoolean,
108     sizeof(Boolean),
109     offset(forcebars),
110     XtRImmediate,
111     (XtPointer)False
112   },
113   {
114     XtNallowHoriz,
115     XtCBoolean,
116     XtRBoolean,
117     sizeof(Boolean),
118     offset(allowhoriz),
119     XtRImmediate,
120     (XtPointer)False
121   },
122   {
123     XtNallowVert,
124     XtCBoolean,
125     XtRBoolean,
126     sizeof(Boolean),
127     offset(allowvert),
128     XtRImmediate,
129     (XtPointer)False
130   },
131   {
132     XtNuseBottom,
133     XtCBoolean,
134     XtRBoolean,
135     sizeof(Boolean),
136     offset(usebottom),
137     XtRImmediate,
138     (XtPointer)False
139   },
140   {
141     XtNuseRight,
142     XtCBoolean,
143     XtRBoolean,
144     sizeof(Boolean),
145     offset(useright),
146     XtRImmediate,
147     (XtPointer)False
148   },
149   {
150     XtNreportCallback,
151     XtCReportCallback,
152     XtRCallback,
153     sizeof(XtPointer),
154     offset(report_callbacks),
155     XtRImmediate,
156     NULL
157   },
158 };
159 #undef offset
160
161 #define Superclass      (&formClassRec)
162 ViewportClassRec viewportClassRec = {
163   /* core */
164   {
165     (WidgetClass)Superclass,            /* superclass */
166     "Viewport",                         /* class_name */
167     sizeof(ViewportRec),                /* widget_size */
168     XawInitializeWidgetSet,             /* class_initialize */
169     NULL,                               /* class_part_init */
170     False,                              /* class_inited */
171     XawViewportInitialize,              /* initialize */
172     NULL,                               /* initialize_hook */
173     XawViewportRealize,                 /* realize */
174     NULL,                               /* actions */
175     0,                                  /* num_actions */
176     resources,                          /* resources */
177     XtNumber(resources),                /* num_resources */
178     NULLQUARK,                          /* xrm_class */
179     True,                               /* compress_motion */
180     True,                               /* compress_exposure */
181     True,                               /* compress_enterleave */
182     False,                              /* visible_interest */
183     NULL,                               /* destroy */
184     XawViewportResize,                  /* resize */
185     XtInheritExpose,                    /* expose */
186     XawViewportSetValues,               /* set_values */
187     NULL,                               /* set_values_hook */
188     XtInheritSetValuesAlmost,           /* set_values_almost */
189     NULL,                               /* get_values_hook */
190     NULL,                               /* accept_focus */
191     XtVersion,                          /* version */
192     NULL,                               /* callback_private */
193     NULL,                               /* tm_table */
194     XawViewportQueryGeometry,           /* query_geometry */
195     XtInheritDisplayAccelerator,        /* display_accelerator */
196     NULL,                               /* extension */
197   },
198   /* composite */
199   {
200     XawViewportGeometryManager,         /* geometry_manager */
201     XawViewportChangeManaged,           /* change_managed */
202     XtInheritInsertChild,               /* insert_child */
203     XtInheritDeleteChild,               /* delete_child */
204     NULL,                               /* extension */
205   },
206   /* constraint */
207   {
208     NULL,                               /* subresourses */
209     0,                                  /* subresource_count */
210     sizeof(ViewportConstraintsRec),     /* constraint_size */
211     XawViewportConstraintInitialize,    /* initialize */
212     NULL,                               /* destroy */
213     NULL,                               /* set_values */
214     NULL,                               /* extension */
215   },
216   /* form */
217   {
218     Layout,                             /* layout */
219   },
220   /* viewport */
221   {
222     NULL,                               /* extension */
223   },
224 };
225
226 WidgetClass viewportWidgetClass = (WidgetClass)&viewportClassRec;
227
228 /*
229  * Implementation
230  */
231 static Widget
232 CreateScrollbar(ViewportWidget w, Bool horizontal)
233 {
234     static Arg barArgs[] = {
235         {XtNorientation,            0},
236         {XtNlength,                 0},
237         {XtNleft,                   0},
238         {XtNright,                  0},
239         {XtNtop,                    0},
240         {XtNbottom,                 0},
241         {XtNmappedWhenManaged,      False},
242     };
243     Widget clip = w->viewport.clip;
244     ViewportConstraints constraints =
245         (ViewportConstraints)clip->core.constraints;
246     Widget bar;
247
248     XtSetArg(barArgs[0], XtNorientation,
249            horizontal ? XtorientHorizontal : XtorientVertical);
250     XtSetArg(barArgs[1], XtNlength,
251            horizontal ? XtWidth(clip) : XtHeight(clip));
252     XtSetArg(barArgs[2], XtNleft,
253            !horizontal && w->viewport.useright ? XtChainRight : XtChainLeft);
254     XtSetArg(barArgs[3], XtNright,
255            !horizontal && !w->viewport.useright ? XtChainLeft : XtChainRight);
256     XtSetArg(barArgs[4], XtNtop,
257            horizontal && w->viewport.usebottom ? XtChainBottom: XtChainTop);
258     XtSetArg(barArgs[5], XtNbottom,
259            horizontal && !w->viewport.usebottom ? XtChainTop: XtChainBottom);
260
261     bar = XtCreateWidget(horizontal ? "horizontal" : "vertical",
262                          scrollbarWidgetClass, (Widget)w,
263                          barArgs, XtNumber(barArgs));
264     XtAddCallback(bar, XtNscrollProc, ScrollUpDownProc, (XtPointer)w);
265     XtAddCallback(bar, XtNjumpProc, ThumbProc, (XtPointer)w);
266
267     if (horizontal) {
268         w->viewport.horiz_bar = bar;
269         constraints->form.vert_base = bar;
270     }
271     else {
272         w->viewport.vert_bar = bar;
273         constraints->form.horiz_base = bar;
274     }
275
276     XtManageChild(bar);
277
278     return (bar);
279 }
280
281 /*ARGSUSED*/
282 static void
283 XawViewportInitialize(Widget request, Widget cnew,
284                       ArgList args, Cardinal *num_args)
285 {
286     ViewportWidget w = (ViewportWidget)cnew;
287     static Arg clip_args[8];
288     Cardinal arg_cnt;
289     Widget h_bar, v_bar;
290     Dimension clip_height, clip_width;
291
292     w->form.default_spacing = 0; /* Reset the default spacing to 0 pixels */
293
294     /*
295      * Initialize all widget pointers to NULL
296      */
297     w->viewport.child = NULL;
298     w->viewport.horiz_bar = w->viewport.vert_bar = NULL;
299
300     /*
301      * Create Clip Widget
302      */
303     arg_cnt = 0;
304     XtSetArg(clip_args[arg_cnt], XtNbackgroundPixmap, None);    arg_cnt++;
305     XtSetArg(clip_args[arg_cnt], XtNborderWidth, 0);            arg_cnt++;
306     XtSetArg(clip_args[arg_cnt], XtNleft, XtChainLeft);         arg_cnt++;
307     XtSetArg(clip_args[arg_cnt], XtNright, XtChainRight);       arg_cnt++;
308     XtSetArg(clip_args[arg_cnt], XtNtop, XtChainTop);           arg_cnt++;
309     XtSetArg(clip_args[arg_cnt], XtNbottom, XtChainBottom);     arg_cnt++;
310     XtSetArg(clip_args[arg_cnt], XtNwidth, XtWidth(w));         arg_cnt++;
311     XtSetArg(clip_args[arg_cnt], XtNheight, XtHeight(w));       arg_cnt++;
312
313     w->viewport.clip = XtCreateManagedWidget("clip", widgetClass, cnew,
314                                              clip_args, arg_cnt);
315
316     if (!w->viewport.forcebars)
317         return;          /* If we are not forcing the bars then we are done */
318
319     if (w->viewport.allowhoriz)
320         (void)CreateScrollbar(w, True);
321     if (w->viewport.allowvert)
322         (void)CreateScrollbar(w, False);
323
324     h_bar = w->viewport.horiz_bar;
325     v_bar = w->viewport.vert_bar;
326
327     /*
328      * Set the clip widget to the correct height
329      */
330     clip_width = XtWidth(w);
331     clip_height = XtHeight(w);
332
333     if (h_bar != NULL &&  XtWidth(w) > XtWidth(h_bar) + XtBorderWidth(h_bar))
334         clip_width -= XtWidth(h_bar) + XtBorderWidth(h_bar);
335
336     if (v_bar != NULL && XtHeight(w) > XtHeight(v_bar) + XtBorderWidth(v_bar))
337         clip_height -= XtHeight(v_bar) + XtBorderWidth(v_bar);
338
339     arg_cnt = 0;
340     XtSetArg(clip_args[arg_cnt], XtNwidth, clip_width); arg_cnt++;
341     XtSetArg(clip_args[arg_cnt], XtNheight, clip_height); arg_cnt++;
342     XtSetValues(w->viewport.clip, clip_args, arg_cnt);
343 }
344
345 /*ARGSUSED*/
346 static void
347 XawViewportConstraintInitialize(Widget request, Widget cnew,
348                                 ArgList args, Cardinal *num_args)
349 {
350     ((ViewportConstraints)cnew->core.constraints)->viewport.reparented = False;
351 }
352
353 static void
354 XawViewportRealize(Widget widget, XtValueMask *value_mask,
355                    XSetWindowAttributes *attributes)
356 {
357     ViewportWidget w = (ViewportWidget)widget;
358     Widget child = w->viewport.child;
359     Widget clip = w->viewport.clip;
360
361     *value_mask |= CWBitGravity;
362     attributes->bit_gravity = NorthWestGravity;
363     (*Superclass->core_class.realize)(widget, value_mask, attributes);
364
365     (*w->core.widget_class->core_class.resize)(widget); /* turn on bars */
366
367     if (child != NULL) {
368         XtMoveWidget(child, 0, 0);
369         XtRealizeWidget(clip);
370         XtRealizeWidget(child);
371         XReparentWindow(XtDisplay(w), XtWindow(child), XtWindow(clip), 0, 0);
372         XtMapWidget(child);
373     }
374 }
375
376 /*ARGSUSED*/
377 static Boolean
378 XawViewportSetValues(Widget current, Widget request, Widget cnew,
379                      ArgList args, Cardinal *num_args)
380 {
381     ViewportWidget w = (ViewportWidget)cnew;
382     ViewportWidget cw = (ViewportWidget)current;
383
384     if (w->viewport.forcebars != cw->viewport.forcebars
385         || w->viewport.allowvert != cw->viewport.allowvert
386         || w->viewport.allowhoriz != cw->viewport.allowhoriz
387         || w->viewport.useright != cw->viewport.useright
388         || w->viewport.usebottom != cw->viewport.usebottom)
389         (*w->core.widget_class->core_class.resize)(cnew); /* Recompute layout */
390
391     return (False);
392 }
393
394 static void
395 XawViewportChangeManaged(Widget widget)
396 {
397     ViewportWidget w = (ViewportWidget)widget;
398     int num_children = w->composite.num_children;
399     Widget child, *childP;
400     int i;
401
402     child = NULL;
403     for (childP = w->composite.children,
404          i = 0; i < num_children;
405          childP++, i++) {
406         if (XtIsManaged(*childP)
407             && *childP != w->viewport.clip
408             && *childP != w->viewport.horiz_bar
409             && *childP != w->viewport.vert_bar) {
410             child = *childP;
411             break;
412         }
413     }
414
415     if (child != w->viewport.child) {
416         w->viewport.child = child;
417         if (child != NULL) {
418             XtResizeWidget(child, XtWidth(child), XtHeight(child), 0);
419             if (XtIsRealized(widget)) {
420                 ViewportConstraints constraints =
421                     (ViewportConstraints)child->core.constraints;
422                 if (!XtIsRealized(child)) {
423                     Window window = XtWindow(w);
424
425                     XtMoveWidget(child, 0, 0);
426                     w->core.window = XtWindow(w->viewport.clip);
427                     XtRealizeWidget(child);
428                     w->core.window = window;
429                     constraints->viewport.reparented = True;
430                 }
431                 else if (!constraints->viewport.reparented) {
432                     XReparentWindow(XtDisplay(w), XtWindow(child),
433                                     XtWindow(w->viewport.clip), 0, 0);
434                     constraints->viewport.reparented = True;
435                     if (child->core.mapped_when_managed)
436                     XtMapWidget(child);
437                 }
438             }
439             GetGeometry(widget, XtWidth(child), XtHeight(child));
440             (*((ViewportWidgetClass)w->core.widget_class)->form_class.layout)
441             ((FormWidget)w, XtWidth(w), XtHeight(w), True /* True? */);
442         }
443     }
444
445 #ifdef notdef
446     (*Superclass->composite_class.change_managed)(widget);
447 #endif
448 }
449
450 static void
451 SetBar(Widget w, int top, unsigned int length, unsigned int total)
452 {
453     XawScrollbarSetThumb(w, (float)top / (float)total,
454                          (float)length / (float)total);
455 }
456
457 static void
458 RedrawThumbs(ViewportWidget w)
459 {
460     Widget child = w->viewport.child;
461     Widget clip = w->viewport.clip;
462
463     if (w->viewport.horiz_bar != NULL)
464         SetBar(w->viewport.horiz_bar, -(int)XtX(child),
465                XtWidth(clip), XtWidth(child));
466
467     if (w->viewport.vert_bar != NULL)
468         SetBar(w->viewport.vert_bar, -(int)XtY(child),
469                XtHeight(clip), XtHeight(child));
470 }
471
472 static void
473 SendReport(ViewportWidget w, unsigned int changed)
474 {
475     XawPannerReport rep;
476
477     if (w->viewport.report_callbacks) {
478         Widget child = w->viewport.child;
479         Widget clip = w->viewport.clip;
480
481         rep.changed = changed;
482         rep.slider_x = -XtX(child);     /* child is canvas */
483         rep.slider_y = -XtY(child);     /* clip is slider */
484         rep.slider_width = XtWidth(clip);
485         rep.slider_height = XtHeight(clip);
486         rep.canvas_width = XtWidth(child);
487         rep.canvas_height = XtHeight(child);
488         XtCallCallbackList((Widget)w, w->viewport.report_callbacks,
489                            (XtPointer)&rep);
490     }
491 }
492
493 static void
494 MoveChild(ViewportWidget w, int x, int y)
495 {
496     Widget child = w->viewport.child;
497     Widget clip = w->viewport.clip;
498
499     /* make sure we never move past right/bottom borders */
500     if (-x + (int)XtWidth(clip) > XtWidth(child))
501         x = -(int)(XtWidth(child) - XtWidth(clip));
502
503     if (-y + (int)XtHeight(clip) > XtHeight(child))
504         y = -(int)(XtHeight(child) - XtHeight(clip));
505
506     /* make sure we never move past left/top borders */
507     if (x >= 0)
508         x = 0;
509     if (y >= 0)
510         y = 0;
511
512     XtMoveWidget(child, x, y);
513     SendReport(w, (XawPRSliderX | XawPRSliderY));
514
515     RedrawThumbs(w);
516 }
517
518 static void
519 ComputeLayout(Widget widget, Bool query, Bool destroy_scrollbars)
520 {
521     ViewportWidget w = (ViewportWidget)widget;
522     Widget child = w->viewport.child;
523     Widget clip = w->viewport.clip;
524     ViewportConstraints constraints =
525         (ViewportConstraints)clip->core.constraints;
526     Bool needshoriz, needsvert;
527     int clip_width, clip_height;
528     XtWidgetGeometry intended;
529
530     if (child == NULL)
531         return;
532
533     clip_width = XtWidth(w);
534     clip_height = XtHeight(w);
535     intended.request_mode = CWBorderWidth;
536     intended.border_width = 0;
537
538     if (w->viewport.forcebars) {
539         needsvert = w->viewport.allowvert;
540         needshoriz = w->viewport.allowhoriz;
541         ComputeWithForceBars(widget, query, &intended,
542                              &clip_width, &clip_height);
543     }
544     else {
545         Dimension prev_width, prev_height;
546         XtGeometryMask prev_mode;
547         XtWidgetGeometry preferred;
548
549         needshoriz = needsvert = False;
550
551         /*
552          * intended.{width,height} caches the eventual child dimensions,
553          * but we don't set the mode bits until after we decide that the
554          * child's preferences are not acceptable
555          */
556         if (!w->viewport.allowhoriz)
557             intended.request_mode |= CWWidth;
558
559         if (XtWidth(child) < clip_width)
560             intended.width = clip_width;
561         else
562             intended.width = XtWidth(child);
563
564         if (XtHeight(child) < clip_height)
565             intended.height = clip_height;
566         else
567             intended.height = XtHeight(child);
568
569         if (!w->viewport.allowvert)
570             intended.request_mode |= CWHeight;
571
572         if (!query) {
573             preferred.width = XtWidth(child);
574             preferred.height = XtHeight(child);
575         }
576         do { /* while intended != prev  */
577             if (query) {
578                 (void)XtQueryGeometry(child, &intended, &preferred);
579                 if (!(preferred.request_mode & CWWidth))
580                     preferred.width = intended.width;
581                 if (!(preferred.request_mode & CWHeight))
582                     preferred.height = intended.height;
583             }
584             prev_width = intended.width;
585             prev_height = intended.height;
586             prev_mode = intended.request_mode;
587             /*
588              * note that having once decided to turn on either bar
589              * we'll not change our mind until we're next resized,
590              * thus avoiding potential oscillations
591              */
592 #define CheckHoriz() \
593             if (w->viewport.allowhoriz &&                               \
594                 preferred.width > clip_width) {                         \
595                 if (!needshoriz) {                                      \
596                     Widget bar;                                         \
597                                                                         \
598                     needshoriz = True;                                  \
599                     if ((bar = w->viewport.horiz_bar) == NULL)          \
600                         bar = CreateScrollbar(w, True);                 \
601                     clip_height -= XtHeight(bar) + XtBorderWidth(bar);  \
602                     if (clip_height < 1)                                \
603                         clip_height = 1;                                \
604                 }                                                       \
605                 intended.width = preferred.width;                       \
606             }
607
608             CheckHoriz();
609             if (w->viewport.allowvert && preferred.height > clip_height) {
610                 if (!needsvert) {
611                     Widget bar;
612                     needsvert = True;
613                     if ((bar = w->viewport.vert_bar) == NULL)
614                         bar = CreateScrollbar(w, False);
615                     clip_width -= XtWidth(bar) + XtBorderWidth(bar);
616                     if (clip_width < 1)
617                         clip_width = 1;
618                     CheckHoriz();
619                 }
620                 intended.height = preferred.height;
621             }
622             if (!w->viewport.allowhoriz || preferred.width < clip_width) {
623                 intended.width = clip_width;
624                 intended.request_mode |= CWWidth;
625             }
626             if (!w->viewport.allowvert || preferred.height < clip_height) {
627                 intended.height = clip_height;
628                 intended.request_mode |= CWHeight;
629             }
630         } while (intended.request_mode != prev_mode
631                  || (intended.request_mode & CWWidth
632                      && intended.width != prev_width)
633                  || (intended.request_mode & CWHeight
634                      && intended.height != prev_height));
635     }
636
637     if (XtIsRealized(clip))
638         XRaiseWindow(XtDisplay(clip), XtWindow(clip));
639
640     XtMoveWidget(clip,
641                  needsvert ? w->viewport.useright ? 0 :
642                  XtWidth(w->viewport.vert_bar)
643                  + XtBorderWidth(w->viewport.vert_bar) : 0,
644                  needshoriz ? w->viewport.usebottom ? 0 :
645                  XtHeight(w->viewport.horiz_bar)
646                  + XtBorderWidth(w->viewport.horiz_bar) : 0);
647     XtResizeWidget(clip, clip_width, clip_height, 0);
648
649     if (w->viewport.horiz_bar != NULL) {
650         Widget bar = w->viewport.horiz_bar;
651
652         if (!needshoriz) {
653             constraints->form.vert_base = NULL;
654             if (destroy_scrollbars) {
655                 XtDestroyWidget(bar);
656                 w->viewport.horiz_bar = NULL;
657             }
658         }
659         else {
660             int bw = XtBorderWidth(bar);
661
662             XtResizeWidget(bar, clip_width, XtHeight(bar), bw);
663             XtMoveWidget(bar,
664                          needsvert && !w->viewport.useright
665                          ? XtWidth(w->viewport.vert_bar) : -bw,
666                          w->viewport.usebottom
667                          ? XtHeight(w) - XtHeight(bar) - bw : -bw);
668             XtSetMappedWhenManaged(bar, True);
669         }
670     }
671
672     if (w->viewport.vert_bar != NULL) {
673         Widget bar = w->viewport.vert_bar;
674
675         if (!needsvert) {
676             constraints->form.horiz_base = NULL;
677             if (destroy_scrollbars) {
678                 XtDestroyWidget(bar);
679                 w->viewport.vert_bar = NULL;
680             }
681         }
682         else {
683             int bw = bar->core.border_width;
684
685             XtResizeWidget(bar, XtWidth(bar), clip_height, bw);
686             XtMoveWidget(bar,
687                         w->viewport.useright
688                         ? XtWidth(w) - XtWidth(bar) - bw : -bw,
689                         needshoriz && !w->viewport.usebottom
690                         ? XtHeight(w->viewport.horiz_bar) : -bw);
691            XtSetMappedWhenManaged(bar, True);
692         }
693     }
694
695     if (child != NULL) {
696         XtResizeWidget(child, intended.width, intended.height, 0);
697         MoveChild(w, needshoriz ? XtX(child) : 0,       needsvert ? XtY(child) : 0);
698     }
699
700     SendReport (w, XawPRAll);
701 }
702
703 /*
704  * Function:
705  *      ComputeWithForceBars
706  *
707  * Parameters:
708  *      widget      - viewport widget
709  *      query       - whether or not to query the child
710  *      intended    - cache of the childs height is stored here
711  *                    (used and returned)
712  *      clip_width  - size of clip window (used and returned)
713  *      clip_height - ""
714  *
715  * Description:
716  *      Computes the layout give forcebars is set.
717  */
718 static void
719 ComputeWithForceBars(Widget widget, Bool query, XtWidgetGeometry *intended,
720                      int *clip_width, int *clip_height)
721 {
722     ViewportWidget w = (ViewportWidget)widget;
723     Widget child = w->viewport.child;
724     XtWidgetGeometry preferred;
725
726     /*
727      * If forcebars then needs = allows = has
728      * Thus if needsvert is set it MUST have a scrollbar
729      */
730     if (w->viewport.allowvert) {
731         if (w->viewport.vert_bar == NULL)
732             w->viewport.vert_bar = CreateScrollbar(w, False);
733
734         *clip_width -= XtWidth(w->viewport.vert_bar) +
735                        XtBorderWidth(w->viewport.vert_bar);
736     }
737
738     if (w->viewport.allowhoriz) {
739         if (w->viewport.horiz_bar == NULL)
740             w->viewport.horiz_bar = CreateScrollbar(w, True);
741
742         *clip_height -= XtHeight(w->viewport.horiz_bar) +
743                         XtBorderWidth(w->viewport.horiz_bar);
744     }
745
746     AssignMax(*clip_width, 1);
747     AssignMax(*clip_height, 1);
748
749     if (!w->viewport.allowvert) {
750         intended->height = *clip_height;
751         intended->request_mode = CWHeight;
752     }
753     if (!w->viewport.allowhoriz) {
754         intended->width = *clip_width;
755         intended->request_mode = CWWidth;
756     }
757
758     if (query) {
759         if (w->viewport.allowvert || w->viewport.allowhoriz) {
760             XtQueryGeometry(child, intended, &preferred);
761
762             if (!(intended->request_mode & CWWidth)) {
763                 if (preferred.request_mode & CWWidth)
764                     intended->width = preferred.width;
765                 else
766                     intended->width = XtWidth(child);
767             }
768
769             if (!(intended->request_mode & CWHeight)) {
770                 if (preferred.request_mode & CWHeight)
771                     intended->height = preferred.height;
772                 else
773                     intended->height = XtHeight(child);
774             }
775         }
776     }
777     else {
778         if (w->viewport.allowvert)
779             intended->height = XtHeight(child);
780         if (w->viewport.allowhoriz)
781             intended->width = XtWidth(child);
782     }
783
784     if (*clip_width > (int)intended->width)
785         intended->width = *clip_width;
786     if (*clip_height > (int)intended->height)
787         intended->height = *clip_height;
788 }
789
790 static void
791 XawViewportResize(Widget widget)
792 {
793     ComputeLayout(widget, True, True);
794 }
795
796 /*ARGSUSED*/
797 static Boolean
798 Layout(FormWidget w, unsigned int width, unsigned int height, Bool force)
799 {
800     ComputeLayout((Widget)w, True, True);
801     w->form.preferred_width = XtWidth(w);
802     w->form.preferred_height = XtHeight(w);
803
804     return (False);
805 }
806
807 static void
808 ScrollUpDownProc(Widget widget, XtPointer closure, XtPointer call_data)
809 {
810     ViewportWidget w = (ViewportWidget)closure;
811     Widget child = w->viewport.child;
812     int pix = (long)call_data;
813     int x, y;
814
815     if (child == NULL)
816         return;
817
818     x = XtX(child) - (widget == w->viewport.horiz_bar ? pix : 0);
819     y = XtY(child) - (widget == w->viewport.vert_bar ? pix : 0);
820     MoveChild(w, x, y);
821 }
822
823 /*ARGSUSED*/
824 static void
825 ThumbProc(Widget widget, XtPointer closure, XtPointer call_data)
826 {
827     ViewportWidget w = (ViewportWidget)closure;
828     Widget child = w->viewport.child;
829     float percent = *(float *)call_data;
830     int x, y;
831
832     if (child == NULL)
833         return;
834
835     if (widget == w->viewport.horiz_bar)
836         x = -percent * XtWidth(child);
837     else
838         x = XtX(child);
839
840     if (widget == w->viewport.vert_bar)
841         y = -percent * XtHeight(child);
842     else
843         y = XtY(child);
844
845     MoveChild(w, x, y);
846 }
847
848 static XtGeometryResult
849 TestSmaller(ViewportWidget w, XtWidgetGeometry *request,
850             XtWidgetGeometry *reply_return)
851 {
852     if (request->width < XtWidth(w) || request->height < XtHeight(w))
853         return (XtMakeGeometryRequest((Widget)w, request, reply_return));
854
855     return (XtGeometryYes);
856 }
857
858 static XtGeometryResult
859 GeometryRequestPlusScrollbar(ViewportWidget w, Bool horizontal,
860                              XtWidgetGeometry *request,
861                              XtWidgetGeometry *reply_return)
862 {
863     Widget sb;
864     XtWidgetGeometry plusScrollbars;
865
866     plusScrollbars = *request;
867     if ((sb = w->viewport.horiz_bar) == NULL)
868         sb = CreateScrollbar(w, horizontal);
869     request->width += XtWidth(sb);
870     request->height += XtHeight(sb);
871     XtDestroyWidget(sb);
872     return (XtMakeGeometryRequest((Widget)w, &plusScrollbars, reply_return));
873 }
874
875 #define WidthChange()   (request->width != XtWidth(w))
876 #define HeightChange()  (request->height != XtHeight(w))
877 static XtGeometryResult
878 QueryGeometry(ViewportWidget w, XtWidgetGeometry *request,
879               XtWidgetGeometry *reply_return)
880 {
881     if (w->viewport.allowhoriz && w->viewport.allowvert)
882         return (TestSmaller(w, request, reply_return));
883
884     else if (w->viewport.allowhoriz && !w->viewport.allowvert) {
885         if (WidthChange() && !HeightChange())
886             return (TestSmaller(w, request, reply_return));
887         else if (!WidthChange() && HeightChange())
888             return (XtMakeGeometryRequest((Widget)w, request, reply_return));
889         else if (WidthChange() && HeightChange())
890             return (GeometryRequestPlusScrollbar(w, True, request, reply_return));
891         else /* !WidthChange() && !HeightChange() */
892             return (XtGeometryYes);
893     }
894     else if (!w->viewport.allowhoriz && w->viewport.allowvert) {
895         if (!WidthChange() && HeightChange())
896             return (TestSmaller(w, request, reply_return));
897         else if (WidthChange() && !HeightChange())
898             return (XtMakeGeometryRequest((Widget)w, request, reply_return));
899         else if (WidthChange() && HeightChange())
900             return (GeometryRequestPlusScrollbar(w, False, request, reply_return));
901         else /* !WidthChange() && !HeightChange() */
902             return (XtGeometryYes);
903     }
904     else /* (!w->viewport.allowhoriz && !w->viewport.allowvert) */
905         return (XtMakeGeometryRequest((Widget)w, request, reply_return));
906 }
907 #undef WidthChange
908 #undef HeightChange
909
910 static XtGeometryResult
911 XawViewportGeometryManager(Widget child, XtWidgetGeometry *request,
912                            XtWidgetGeometry *reply)
913 {
914     ViewportWidget w = (ViewportWidget)child->core.parent;
915     Bool rWidth = (request->request_mode & CWWidth) != 0;
916     Bool rHeight = (request->request_mode & CWHeight) != 0;
917     XtWidgetGeometry allowed;
918     XtGeometryResult result;
919     Bool reconfigured;
920     Bool child_changed_size;
921     unsigned int height_remaining;
922
923     if (request->request_mode & XtCWQueryOnly)
924         return (QueryGeometry(w, request, reply));
925
926     if (child != w->viewport.child
927         || request->request_mode & ~(CWWidth | CWHeight | CWBorderWidth)
928         || ((request->request_mode & CWBorderWidth)
929             && request->border_width > 0))
930         return (XtGeometryNo);
931
932     allowed = *request;
933
934     reconfigured = GetGeometry((Widget)w,
935                                 rWidth ? request->width : XtWidth(w),
936                                 rHeight ? request->height : XtHeight(w));
937
938     child_changed_size = (rWidth && XtWidth(child) != request->width) ||
939                          (rHeight && XtHeight(child) != request->height);
940
941     height_remaining = XtHeight(w);
942     if (rWidth && XtWidth(w) != request->width) {
943         if (w->viewport.allowhoriz && request->width > XtWidth(w)) {
944             /* horizontal scrollbar will be needed so possibly reduce height */
945             Widget bar;
946
947             if ((bar = w->viewport.horiz_bar) == NULL)
948                 bar = CreateScrollbar(w, True);
949             height_remaining -= XtHeight(bar) + XtBorderWidth(bar);
950             reconfigured = True;
951         }
952         else
953             allowed.width = XtWidth(w);
954     }
955     if (rHeight && height_remaining != request->height) {
956         if (w->viewport.allowvert && request->height > height_remaining) {
957             /* vertical scrollbar will be needed, so possibly reduce width */
958             if (!w->viewport.allowhoriz || request->width < XtWidth(w)) {
959                 Widget bar;
960
961                 if ((bar = w->viewport.vert_bar) == NULL)
962                     bar = CreateScrollbar(w, False);
963                 if (!rWidth) {
964                     allowed.width = XtWidth(w);
965                     allowed.request_mode |= CWWidth;
966                 }
967                 if (allowed.width  >  XtWidth(bar) + XtBorderWidth(bar))
968                     allowed.width -= XtWidth(bar) + XtBorderWidth(bar);
969                 else
970                     allowed.width = 1;
971                 reconfigured = True;
972             }
973         }
974         else
975             allowed.height = height_remaining;
976     }
977
978     if (allowed.width != request->width || allowed.height != request->height) {
979         *reply = allowed;
980         result = XtGeometryAlmost;
981     }
982     else {
983         if (rWidth)
984             XtWidth(child) = request->width;
985         if (rHeight)
986             XtHeight(child) = request->height;
987         result = XtGeometryYes;
988     }
989
990     if (reconfigured || child_changed_size)
991         ComputeLayout((Widget)w, False, result == XtGeometryYes);
992
993     return (result);
994 }
995
996 static Bool
997 GetGeometry(Widget w, unsigned int width, unsigned int height)
998 {
999     XtWidgetGeometry geometry, return_geom;
1000     XtGeometryResult result;
1001
1002     if (width == XtWidth(w) && height == XtHeight(w))
1003         return (False);
1004
1005     geometry.request_mode = CWWidth | CWHeight;
1006     geometry.width = width;
1007     geometry.height = height;
1008
1009     if (XtIsRealized(w)) {
1010         if (((ViewportWidget)w)->viewport.allowhoriz && width > XtWidth(w))
1011             geometry.width = XtWidth(w);
1012         if (((ViewportWidget)w)->viewport.allowvert && height > XtHeight(w))
1013             geometry.height = XtHeight(w);
1014     }
1015     else {
1016         /* This is the Realize call; we'll inherit a w&h iff none currently */
1017         if (XtWidth(w) != 0) {
1018             if (XtHeight(w) != 0)
1019                 return (False);
1020             geometry.width = XtWidth(w);
1021         }
1022         if (XtHeight(w) != 0)
1023             geometry.height = XtHeight(w);
1024     }
1025
1026     result = XtMakeGeometryRequest(w, &geometry, &return_geom);
1027     if (result == XtGeometryAlmost)
1028         result = XtMakeGeometryRequest(w, &return_geom, NULL);
1029
1030     return (result == XtGeometryYes);
1031 }
1032
1033 static XtGeometryResult
1034 XawViewportQueryGeometry(Widget w, XtWidgetGeometry *constraints,
1035                          XtWidgetGeometry *reply)
1036 {
1037     if (((ViewportWidget)w)->viewport.child != NULL)
1038         return (XtQueryGeometry(((ViewportWidget)w)->viewport.child,
1039                                 constraints, reply));
1040
1041     return (XtGeometryYes);
1042 }
1043
1044 void
1045 XawViewportSetLocation
1046 (
1047  Widget gw,
1048 #if NeedWidePrototypes
1049  double xoff, double yoff
1050 #else
1051  float xoff, float yoff
1052 #endif
1053  )
1054 {
1055     ViewportWidget w = (ViewportWidget)gw;
1056     Widget child = w->viewport.child;
1057     int x, y;
1058
1059     if (xoff > 1.0)                     /* scroll to right */
1060         x = XtWidth(child);
1061     else if (xoff < 0.0)                /* if the offset is < 0.0 nothing */
1062         x = XtX(child);
1063     else
1064         x = (float)XtWidth(child) * xoff;
1065
1066     if (yoff > 1.0)
1067         y = XtHeight(child);
1068     else if (yoff < 0.0)
1069         y = XtY(child);
1070     else
1071         y = (float)XtHeight(child) * yoff;
1072
1073     MoveChild (w, -x, -y);
1074 }
1075
1076 void
1077 XawViewportSetCoordinates(Widget gw,
1078 #if NeedWidePrototypes
1079         int x, int y
1080 #else
1081         Position x, Position y
1082 #endif
1083 )
1084 {
1085     ViewportWidget w = (ViewportWidget)gw;
1086     Widget child = w->viewport.child;
1087
1088     if (x > XtWidth(child))
1089         x = XtWidth(child);
1090     else if (x < 0)
1091         x = XtX(child);
1092
1093     if (y > XtHeight(child))
1094         y = XtHeight(child);
1095     else if (y < 0)
1096         y = XtY(child);
1097
1098     MoveChild (w, -x, -y);
1099 }