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