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