Scrollbar.c revision 994689c1
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/Drawing.h> 54#include <X11/Xaw/ScrollbarP.h> 55#include <X11/Xaw/XawInit.h> 56#include "Private.h" 57 58#define NoButton -1 59#define PICKLENGTH(widget, x, y) \ 60(((widget)->scrollbar.orientation == XtorientHorizontal) ? (x) : (y)) 61 62/* 63 * Class Methods 64 */ 65static void XawScrollbarClassInitialize(void); 66static void XawScrollbarDestroy(Widget); 67static void XawScrollbarInitialize(Widget, Widget, ArgList, Cardinal*_args); 68static void XawScrollbarRealize(Widget, Mask*, XSetWindowAttributes*); 69static void XawScrollbarRedisplay(Widget, XEvent*, Region); 70static void XawScrollbarResize(Widget); 71static Boolean XawScrollbarSetValues(Widget, Widget, Widget, 72 ArgList, Cardinal*); 73 74/* 75 * Prototypes 76 */ 77static Boolean CompareEvents(XEvent*, XEvent*); 78static void CreateGC(Widget); 79static float FloatInRange(float, float, float); 80static float FractionLoc(ScrollbarWidget, int, int); 81static void ExtractPosition(XEvent*, Position*, Position*); 82static int InRange(int, int, int); 83static void FillArea(ScrollbarWidget, int, int, int); 84static Bool LookAhead(Widget, XEvent*); 85static void PaintThumb(ScrollbarWidget); 86static Bool PeekNotifyEvent(Display*, XEvent*, char*); 87static void SetDimensions(ScrollbarWidget); 88 89/* 90 * Actions 91 */ 92static void EndScroll(Widget, XEvent*, String*, Cardinal*); 93static void MoveThumb(Widget, XEvent*, String*, Cardinal*); 94static void NotifyScroll(Widget, XEvent*, String*, Cardinal*); 95static void NotifyThumb(Widget, XEvent*, String*, Cardinal*); 96static void StartScroll(Widget, XEvent*, String*, Cardinal*); 97 98/* 99 * Initialization 100 */ 101static char defaultTranslations[] = 102"<Btn1Down>:" "StartScroll(Forward)\n" 103"<Btn2Down>:" "StartScroll(Continuous) MoveThumb() NotifyThumb()\n" 104"<Btn3Down>:" "StartScroll(Backward)\n" 105"<Btn2Motion>:" "MoveThumb() NotifyThumb()\n" 106"<BtnUp>:" "NotifyScroll(Proportional) EndScroll()\n"; 107 108static float floatZero = 0.0; 109 110#define Offset(field) XtOffsetOf(ScrollbarRec, field) 111 112static XtResource resources[] = { 113 { 114 XtNlength, 115 XtCLength, 116 XtRDimension, 117 sizeof(Dimension), 118 Offset(scrollbar.length), 119 XtRImmediate, 120 (XtPointer)1 121 }, 122 { 123 XtNthickness, 124 XtCThickness, 125 XtRDimension, 126 sizeof(Dimension), 127 Offset(scrollbar.thickness), 128 XtRImmediate, 129 (XtPointer)14 130 }, 131 { 132 XtNorientation, 133 XtCOrientation, 134 XtROrientation, 135 sizeof(XtOrientation), 136 Offset(scrollbar.orientation), 137 XtRImmediate, 138 (XtPointer)XtorientVertical 139 }, 140 { 141 XtNscrollProc, 142 XtCCallback, 143 XtRCallback, 144 sizeof(XtPointer), 145 Offset(scrollbar.scrollProc), 146 XtRCallback, 147 NULL 148 }, 149 { 150 XtNthumbProc, 151 XtCCallback, 152 XtRCallback, 153 sizeof(XtPointer), 154 Offset(scrollbar.thumbProc), 155 XtRCallback, 156 NULL 157 }, 158 { 159 XtNjumpProc, 160 XtCCallback, 161 XtRCallback, 162 sizeof(XtPointer), 163 Offset(scrollbar.jumpProc), 164 XtRCallback, 165 NULL 166 }, 167 { 168 XtNthumb, 169 XtCThumb, 170 XtRBitmap, 171 sizeof(Pixmap), 172 Offset(scrollbar.thumb), 173 XtRImmediate, 174 (XtPointer)XtUnspecifiedPixmap 175 }, 176 { 177 XtNforeground, 178 XtCForeground, 179 XtRPixel, 180 sizeof(Pixel), 181 Offset(scrollbar.foreground), 182 XtRString, 183 XtDefaultForeground 184 }, 185 { 186 XtNshown, 187 XtCShown, 188 XtRFloat, 189 sizeof(float), 190 Offset(scrollbar.shown), 191 XtRFloat, 192 (XtPointer)&floatZero 193 }, 194 { 195 XtNtopOfThumb, 196 XtCTopOfThumb, 197 XtRFloat, 198 sizeof(float), 199 Offset(scrollbar.top), 200 XtRFloat, 201 (XtPointer)&floatZero 202 }, 203 { 204 XtNscrollVCursor, 205 XtCCursor, 206 XtRCursor, 207 sizeof(Cursor), 208 Offset(scrollbar.verCursor), 209 XtRString, 210 "sb_v_double_arrow" 211 }, 212 { 213 XtNscrollHCursor, 214 XtCCursor, 215 XtRCursor, 216 sizeof(Cursor), 217 Offset(scrollbar.horCursor), 218 XtRString, 219 "sb_h_double_arrow" 220 }, 221 { 222 XtNscrollUCursor, 223 XtCCursor, 224 XtRCursor, 225 sizeof(Cursor), 226 Offset(scrollbar.upCursor), 227 XtRString, 228 "sb_up_arrow" 229 }, 230 { 231 XtNscrollDCursor, 232 XtCCursor, 233 XtRCursor, 234 sizeof(Cursor), 235 Offset(scrollbar.downCursor), 236 XtRString, 237 "sb_down_arrow" 238 }, 239 { 240 XtNscrollLCursor, 241 XtCCursor, 242 XtRCursor, 243 sizeof(Cursor), 244 Offset(scrollbar.leftCursor), 245 XtRString, 246 "sb_left_arrow" 247 }, 248 { 249 XtNscrollRCursor, 250 XtCCursor, 251 XtRCursor, 252 sizeof(Cursor), 253 Offset(scrollbar.rightCursor), 254 XtRString, 255 "sb_right_arrow" 256 }, 257 { 258 XtNminimumThumb, 259 XtCMinimumThumb, 260 XtRDimension, 261 sizeof(Dimension), 262 Offset(scrollbar.min_thumb), 263 XtRImmediate, 264 (XtPointer)7 265 }, 266}; 267#undef Offset 268 269static XtActionsRec actions[] = { 270 {"StartScroll", StartScroll}, 271 {"MoveThumb", MoveThumb}, 272 {"NotifyThumb", NotifyThumb}, 273 {"NotifyScroll", NotifyScroll}, 274 {"EndScroll", EndScroll}, 275}; 276 277#define Superclass (&simpleClassRec) 278ScrollbarClassRec scrollbarClassRec = { 279 /* core */ 280 { 281 (WidgetClass)&simpleClassRec, /* superclass */ 282 "Scrollbar", /* class_name */ 283 sizeof(ScrollbarRec), /* widget_size */ 284 XawScrollbarClassInitialize, /* class_initialize */ 285 NULL, /* class_part_init */ 286 False, /* class_inited */ 287 XawScrollbarInitialize, /* initialize */ 288 NULL, /* initialize_hook */ 289 XawScrollbarRealize, /* realize */ 290 actions, /* actions */ 291 XtNumber(actions), /* num_actions */ 292 resources, /* resources */ 293 XtNumber(resources), /* num_resources */ 294 NULLQUARK, /* xrm_class */ 295 True, /* compress_motion */ 296 True, /* compress_exposure */ 297 True, /* compress_enterleave */ 298 False, /* visible_interest */ 299 XawScrollbarDestroy, /* destroy */ 300 XawScrollbarResize, /* resize */ 301 XawScrollbarRedisplay, /* expose */ 302 XawScrollbarSetValues, /* set_values */ 303 NULL, /* set_values_hook */ 304 XtInheritSetValuesAlmost, /* set_values_almost */ 305 NULL, /* get_values_hook */ 306 NULL, /* accept_focus */ 307 XtVersion, /* version */ 308 NULL, /* callback_private */ 309 defaultTranslations, /* tm_table */ 310 XtInheritQueryGeometry, /* query_geometry */ 311 XtInheritDisplayAccelerator, /* display_accelerator */ 312 NULL, /* extension */ 313 }, 314 /* simple */ 315 { 316 XtInheritChangeSensitive, /* change_sensitive */ 317 }, 318 /* scrollbar */ 319 { 320 NULL, /* extension */ 321 }, 322}; 323 324WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec; 325 326/* 327 * Implementation 328 */ 329static void 330XawScrollbarClassInitialize(void) 331{ 332 XawInitializeWidgetSet(); 333 XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation, 334 NULL, 0); 335 XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString, 336 NULL, 0, XtCacheNone, NULL); 337} 338 339/* 340 * Make sure the first number is within the range specified by the other 341 * two numbers. 342 */ 343static int 344InRange(int num, int small, int big) 345{ 346 return ((num < small) ? small : ((num > big) ? big : num)); 347} 348 349/* 350 * Same as above, but for floating numbers 351 */ 352static float 353FloatInRange(float num, float small, float big) 354{ 355 return ((num < small) ? small : ((num > big) ? big : num)); 356} 357 358/* Fill the area specified by top and bottom with the given pattern */ 359static float 360FractionLoc(ScrollbarWidget w, int x, int y) 361{ 362 float result; 363 364 result = PICKLENGTH(w, x / (float)XtWidth(w), y / (float)XtHeight(w)); 365 366 return (FloatInRange(result, 0.0, 1.0)); 367} 368 369static void 370FillArea(ScrollbarWidget w, int top, int bottom, int thumb) 371{ 372 Dimension length; 373 374 top = XawMax(1, top); 375 if (w->scrollbar.orientation == XtorientHorizontal) 376 bottom = XawMin(bottom, XtWidth(w) - 1); 377 else 378 bottom = XawMin(bottom, XtHeight(w) - 1); 379 380 if (bottom <= top) 381 return; 382 383 length = bottom - top; 384 385 switch(thumb) { 386 /* Fill the new Thumb location */ 387 case 1: 388 if (w->scrollbar.orientation == XtorientHorizontal) 389 XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc, 390 top, 1, length, XtHeight(w) - 2); 391 else 392 XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc, 393 1, top, XtWidth(w) - 2, length); 394 break; 395 /* Clear the old Thumb location */ 396 case 0: 397 if (w->scrollbar.orientation == XtorientHorizontal) 398 XClearArea(XtDisplay(w), XtWindow(w), 399 top, 1, length, XtHeight(w) - 2, False); 400 else 401 XClearArea(XtDisplay(w), XtWindow(w), 402 1, top, XtWidth(w) - 2, length, False); 403 break; 404 } 405} 406 407 408/* Paint the thumb in the area specified by w->top and 409 w->shown. The old area is erased. The painting and 410 erasing is done cleverly so that no flickering will occur. */ 411static void 412PaintThumb(ScrollbarWidget w) 413{ 414 Position oldtop, oldbot, newtop, newbot; 415 416 oldtop = w->scrollbar.topLoc; 417 oldbot = oldtop + w->scrollbar.shownLength; 418 newtop = w->scrollbar.length * w->scrollbar.top; 419 newbot = newtop + (int)(w->scrollbar.length * w->scrollbar.shown); 420 if (newbot < newtop + (int)w->scrollbar.min_thumb) 421 newbot = newtop + w->scrollbar.min_thumb; 422 w->scrollbar.topLoc = newtop; 423 w->scrollbar.shownLength = newbot - newtop; 424 425 if (XtIsRealized((Widget)w)) { 426 if (newtop < oldtop) 427 FillArea(w, newtop, XawMin(newbot, oldtop), 1); 428 if (newtop > oldtop) 429 FillArea(w, oldtop, XawMin(newtop, oldbot), 0); 430 if (newbot < oldbot) 431 FillArea(w, XawMax(newbot, oldtop), oldbot, 0); 432 if (newbot > oldbot) 433 FillArea(w, XawMax(newtop, oldbot), newbot, 1); 434 } 435} 436 437static void 438SetDimensions(ScrollbarWidget w) 439{ 440 if (w->scrollbar.orientation == XtorientVertical) { 441 w->scrollbar.length = XtHeight(w); 442 w->scrollbar.thickness = XtWidth(w); 443 } 444 else { 445 w->scrollbar.length = XtWidth(w); 446 w->scrollbar.thickness = XtHeight(w); 447 } 448} 449 450static void 451XawScrollbarDestroy(Widget w) 452{ 453 ScrollbarWidget sbw = (ScrollbarWidget)w; 454 455 XtReleaseGC(w, sbw->scrollbar.gc); 456} 457 458static void 459CreateGC(Widget w) 460{ 461 ScrollbarWidget sbw = (ScrollbarWidget)w; 462 XGCValues gcValues; 463 XtGCMask mask; 464 unsigned int depth = 1; 465 466 if (sbw->scrollbar.thumb == XtUnspecifiedPixmap) 467 sbw->scrollbar.thumb = XmuCreateStippledPixmap(XtScreen(w), 468 (Pixel)1, (Pixel)0, 469 depth); 470 else if (sbw->scrollbar.thumb != None) { 471 Window root; 472 int x, y; 473 unsigned int width, height, bw; 474 475 XGetGeometry(XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y, 476 &width, &height, &bw, &depth); 477 } 478 479 gcValues.foreground = sbw->scrollbar.foreground; 480 gcValues.background = sbw->core.background_pixel; 481 mask = GCForeground | GCBackground; 482 483 if (sbw->scrollbar.thumb != None) { 484 if (depth == 1) { 485 gcValues.fill_style = FillOpaqueStippled; 486 gcValues.stipple = sbw->scrollbar.thumb; 487 mask |= GCFillStyle | GCStipple; 488 } 489 else { 490 gcValues.fill_style = FillTiled; 491 gcValues.tile = sbw->scrollbar.thumb; 492 mask |= GCFillStyle | GCTile; 493 } 494 } 495 sbw->scrollbar.gc = XtGetGC(w, mask, &gcValues); 496} 497 498/* ARGSUSED */ 499static void 500XawScrollbarInitialize(Widget request, Widget cnew, 501 ArgList args, Cardinal *num_args) 502{ 503 ScrollbarWidget w = (ScrollbarWidget)cnew; 504 505 CreateGC(cnew); 506 507 if (XtWidth(w) == 0) 508 XtWidth(w) = w->scrollbar.orientation == XtorientVertical ? 509 w->scrollbar.thickness : w->scrollbar.length; 510 511 if (XtHeight(w) == 0) 512 XtHeight(w) = w->scrollbar.orientation == XtorientHorizontal ? 513 w->scrollbar.thickness : w->scrollbar.length; 514 515 SetDimensions(w); 516 w->scrollbar.direction = 0; 517 w->scrollbar.topLoc = 0; 518 w->scrollbar.shownLength = w->scrollbar.min_thumb; 519} 520 521static void 522XawScrollbarRealize(Widget gw, Mask *valueMask, 523 XSetWindowAttributes *attributes) 524{ 525 ScrollbarWidget w = (ScrollbarWidget)gw; 526 527 w->scrollbar.inactiveCursor = w->scrollbar.orientation == XtorientVertical ? 528 w->scrollbar.verCursor : w->scrollbar.horCursor; 529 530 XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL); 531 532 /* 533 * The Simple widget actually stuffs the value in the valuemask 534 */ 535 (*scrollbarWidgetClass->core_class.superclass->core_class.realize) 536 (gw, valueMask, attributes); 537} 538 539/*ARGSUSED*/ 540static Boolean 541XawScrollbarSetValues(Widget current, Widget request, Widget desired, 542 ArgList args, Cardinal *num_args) 543{ 544 ScrollbarWidget w = (ScrollbarWidget)current; 545 ScrollbarWidget dw = (ScrollbarWidget)desired; 546 Boolean redraw = False; 547 548 /* 549 * If these values are outside the acceptable range ignore them... 550 */ 551 if (dw->scrollbar.top < 0.0 || dw->scrollbar.top > 1.0) 552 dw->scrollbar.top = w->scrollbar.top; 553 554 if (dw->scrollbar.shown < 0.0 || dw->scrollbar.shown > 1.0) 555 dw->scrollbar.shown = w->scrollbar.shown; 556 557 if (XtIsRealized (desired)) { 558 if (w->scrollbar.foreground != dw->scrollbar.foreground || 559 w->core.background_pixel != dw->core.background_pixel || 560 w->scrollbar.thumb != dw->scrollbar.thumb) { 561 XtReleaseGC((Widget)dw, w->scrollbar.gc); 562 CreateGC((Widget)dw); 563 redraw = True; 564 } 565 if (w->scrollbar.top != dw->scrollbar.top || 566 w->scrollbar.shown != dw->scrollbar.shown) 567 redraw = True; 568 } 569 570 return (redraw); 571} 572 573static void 574XawScrollbarResize(Widget gw) 575{ 576 /* ForgetGravity has taken care of background, but thumb may 577 * have to move as a result of the new size. */ 578 SetDimensions((ScrollbarWidget)gw); 579 XawScrollbarRedisplay(gw, NULL, NULL); 580} 581 582/*ARGSUSED*/ 583static void 584XawScrollbarRedisplay(Widget gw, XEvent *event, Region region) 585{ 586 ScrollbarWidget w = (ScrollbarWidget)gw; 587 int x, y; 588 unsigned int width, height; 589 590 if (Superclass->core_class.expose) 591 (*Superclass->core_class.expose)(gw, event, region); 592 593 if (w->scrollbar.orientation == XtorientHorizontal) { 594 x = w->scrollbar.topLoc; 595 y = 1; 596 width = w->scrollbar.shownLength; 597 height = XtHeight(w) - 2; 598 } 599 else { 600 x = 1; 601 y = w->scrollbar.topLoc; 602 width = XtWidth(w) - 2; 603 height = w->scrollbar.shownLength; 604 } 605 606 if (region == NULL || 607 XRectInRegion(region, x, y, width, height) != RectangleOut) { 608 /* Forces entire thumb to be painted */ 609 w->scrollbar.topLoc = -(w->scrollbar.length + 1); 610 PaintThumb(w); 611 } 612} 613 614/*ARGSUSED*/ 615static void 616StartScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params) 617{ 618 ScrollbarWidget w = (ScrollbarWidget)gw; 619 Cursor cursor; 620 char direction; 621 622 if (w->scrollbar.direction != 0) /* if we're already scrolling */ 623 return; 624 if (*num_params > 0) 625 direction = *params[0]; 626 else 627 direction = 'C'; 628 629 w->scrollbar.direction = direction; 630 631 switch(direction) { 632 case 'B': 633 case 'b': 634 cursor = w->scrollbar.orientation == XtorientVertical ? 635 w->scrollbar.downCursor : w->scrollbar.rightCursor; 636 break; 637 case 'F': 638 case 'f': 639 cursor = w->scrollbar.orientation == XtorientVertical ? 640 w->scrollbar.upCursor : w->scrollbar.leftCursor; 641 break; 642 case 'C': 643 case 'c': 644 cursor = w->scrollbar.orientation == XtorientVertical ? 645 w->scrollbar.rightCursor : w->scrollbar.upCursor; 646 break; 647 default: 648 return; /* invalid invocation */ 649 } 650 651 XtVaSetValues(gw, XtNcursor, cursor, NULL); 652 653 XFlush(XtDisplay(w)); 654} 655 656static Boolean 657CompareEvents(XEvent *oldEvent, XEvent *newEvent) 658{ 659#define Check(field) if (newEvent->field != oldEvent->field) return (False) 660 661 Check(xany.display); 662 Check(xany.type); 663 Check(xany.window); 664 665 switch(newEvent->type) { 666 case MotionNotify: 667 Check(xmotion.state); 668 break; 669 case ButtonPress: 670 case ButtonRelease: 671 Check(xbutton.state); 672 Check(xbutton.button); 673 break; 674 case KeyPress: 675 case KeyRelease: 676 Check(xkey.state); 677 Check(xkey.keycode); 678 break; 679 case EnterNotify: 680 case LeaveNotify: 681 Check(xcrossing.mode); 682 Check(xcrossing.detail); 683 Check(xcrossing.state); 684 break; 685 } 686#undef Check 687 688 return (True); 689} 690 691struct EventData { 692 XEvent *oldEvent; 693 int count; 694}; 695 696static Bool 697PeekNotifyEvent(Display *dpy, XEvent *event, char *args) 698{ 699 struct EventData *eventData = (struct EventData*)args; 700 701 return (++eventData->count == QLength(dpy) /* since PeekIf blocks */ 702 || CompareEvents(event, eventData->oldEvent)); 703} 704 705static Bool 706LookAhead(Widget w, XEvent *event) 707{ 708 XEvent newEvent; 709 struct EventData eventData; 710 711 if (QLength(XtDisplay(w)) == 0) 712 return (False); 713 714 eventData.count = 0; 715 eventData.oldEvent = event; 716 717 XPeekIfEvent(XtDisplay(w), &newEvent, PeekNotifyEvent, (char*)&eventData); 718 719 if (CompareEvents(event, &newEvent)) 720 return (True); 721 722 return (False); 723} 724 725static void 726ExtractPosition(XEvent *event, Position *x, Position *y) 727{ 728 switch(event->type) { 729 case MotionNotify: 730 *x = event->xmotion.x; 731 *y = event->xmotion.y; 732 break; 733 case ButtonPress: 734 case ButtonRelease: 735 *x = event->xbutton.x; 736 *y = event->xbutton.y; 737 break; 738 case KeyPress: 739 case KeyRelease: 740 *x = event->xkey.x; 741 *y = event->xkey.y; 742 break; 743 case EnterNotify: 744 case LeaveNotify: 745 *x = event->xcrossing.x; 746 *y = event->xcrossing.y; 747 break; 748 default: 749 *x = 0; 750 *y = 0; 751 break; 752 } 753} 754 755static void 756NotifyScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params) 757{ 758 ScrollbarWidget w = (ScrollbarWidget)gw; 759 long call_data = 0; 760 char style; 761 Position x, y; 762 763 if (w->scrollbar.direction == 0) /* if no StartScroll */ 764 return; 765 766 if (LookAhead(gw, event)) 767 return; 768 769 if (*num_params > 0) 770 style = *params[0]; 771 else 772 style = 'P'; 773 774 switch(style) { 775 case 'P': /* Proportional */ 776 case 'p': 777 ExtractPosition(event, &x, &y); 778 call_data = InRange(PICKLENGTH(w, x, y), 0, (int)w->scrollbar.length); 779 break; 780 case 'F': /* FullLength */ 781 case 'f': 782 call_data = w->scrollbar.length; 783 break; 784 } 785 786 switch(w->scrollbar.direction) { 787 case 'B': 788 case 'b': 789 call_data = -call_data; 790 /*FALLTHROUGH*/ 791 case 'F': 792 case 'f': 793 XtCallCallbacks(gw, XtNscrollProc, (XtPointer)call_data); 794 break; 795 case 'C': 796 case 'c': /* NotifyThumb has already called the thumbProc(s) */ 797 break; 798 } 799} 800 801/*ARGSUSED*/ 802static void 803EndScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params) 804{ 805 ScrollbarWidget w = (ScrollbarWidget)gw; 806 807 XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL); 808 XFlush(XtDisplay(w)); /* make sure it get propogated */ 809 810 w->scrollbar.direction = 0; 811} 812 813/*ARGSUSED*/ 814static void 815MoveThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params) 816{ 817 ScrollbarWidget w = (ScrollbarWidget)gw; 818 Position x, y; 819 820 if (w->scrollbar.direction == 0) /* if no StartScroll */ 821 return; 822 823 if (LookAhead(gw, event)) 824 return; 825 826 if (!event->xmotion.same_screen) 827 return; 828 829 ExtractPosition(event, &x, &y); 830 w->scrollbar.top = FractionLoc(w, x, y); 831} 832 833/*ARGSUSED*/ 834static void 835NotifyThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params) 836{ 837 ScrollbarWidget w = (ScrollbarWidget)gw; 838 union { 839 XtPointer xtp; 840 float xtf; 841 } xtpf; 842 843 if (w->scrollbar.direction == 0) /* if no StartScroll */ 844 return; 845 846 if (LookAhead(gw, event)) 847 return; 848 849 /* thumbProc is not pretty, but is necessary for backwards 850 compatibility on those architectures for which it work{s,ed}; 851 the intent is to pass a (truncated) float by value. */ 852 xtpf.xtf = w->scrollbar.top; 853 XtCallCallbacks(gw, XtNthumbProc, xtpf.xtp); 854 XtCallCallbacks(gw, XtNjumpProc, (XtPointer)&w->scrollbar.top); 855 856 PaintThumb(w); 857} 858 859/* 860 * Public routines 861 */ 862/* Set the scroll bar to the given location. */ 863void 864XawScrollbarSetThumb(Widget gw, 865#if NeedWidePrototypes 866 double top, double shown 867#else 868 float top, float shown 869#endif 870 ) 871{ 872 ScrollbarWidget w = (ScrollbarWidget)gw; 873 874 if (w->scrollbar.direction == 'c') /* if still thumbing */ 875 return; 876 877 w->scrollbar.top = top > 1.0 ? 1.0 : top >= 0.0 ? top : w->scrollbar.top; 878 879 w->scrollbar.shown = shown > 1.0 ? 1.0 : shown >= 0.0 ? 880 shown : w->scrollbar.shown; 881 PaintThumb(w); 882} 883