1/* 2 * tkWinScrollbar.c -- 3 * 4 * This file implements the Windows specific portion of the scrollbar 5 * widget. 6 * 7 * Copyright (c) 1996 by Sun Microsystems, Inc. 8 * 9 * See the file "license.terms" for information on usage and redistribution of 10 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id$ 13 */ 14 15#include "tkWinInt.h" 16#include "tkScrollbar.h" 17 18/* 19 * The following constant is used to specify the maximum scroll position. This 20 * value is limited by the Win32 API to either 16-bits or 32-bits, depending 21 * on the context. For now we'll just use a value small enough to fit in 22 * 16-bits, but which gives us 4-digits of precision. 23 */ 24 25#define MAX_SCROLL 10000 26 27/* 28 * Declaration of Windows specific scrollbar structure. 29 */ 30 31typedef struct WinScrollbar { 32 TkScrollbar info; /* Generic scrollbar info. */ 33 WNDPROC oldProc; /* Old window procedure. */ 34 int lastVertical; /* 1 if was vertical at last refresh. */ 35 HWND hwnd; /* Current window handle. */ 36 int winFlags; /* Various flags; see below. */ 37} WinScrollbar; 38 39/* 40 * Flag bits for native scrollbars: 41 * 42 * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle 43 * of a modal loop. 44 * ALREADY_DEAD: Non-zero means this scrollbar has been 45 * destroyed, but has not been cleaned up. 46 */ 47 48#define IN_MODAL_LOOP 1 49#define ALREADY_DEAD 2 50 51/* 52 * Cached system metrics used to determine scrollbar geometry. 53 */ 54 55static int initialized = 0; 56static int hArrowWidth, hThumb; /* Horizontal control metrics. */ 57static int vArrowWidth, vArrowHeight, vThumb; /* Vertical control metrics. */ 58 59TCL_DECLARE_MUTEX(winScrlbrMutex) 60 61/* 62 * This variable holds the default width for a scrollbar in string form for 63 * use in a Tk_ConfigSpec. 64 */ 65 66static char defWidth[TCL_INTEGER_SPACE]; 67 68/* 69 * Declarations for functions defined in this file. 70 */ 71 72static Window CreateProc(Tk_Window tkwin, Window parent, 73 ClientData instanceData); 74static void ModalLoopProc(Tk_Window tkwin, XEvent *eventPtr); 75static int ScrollbarBindProc(ClientData clientData, 76 Tcl_Interp *interp, XEvent *eventPtr, 77 Tk_Window tkwin, KeySym keySym); 78static LRESULT CALLBACK ScrollbarProc(HWND hwnd, UINT message, WPARAM wParam, 79 LPARAM lParam); 80static void UpdateScrollbar(WinScrollbar *scrollPtr); 81static void UpdateScrollbarMetrics(void); 82 83/* 84 * The class procedure table for the scrollbar widget. 85 */ 86 87Tk_ClassProcs tkpScrollbarProcs = { 88 sizeof(Tk_ClassProcs), /* size */ 89 NULL, /* worldChangedProc */ 90 CreateProc, /* createProc */ 91 ModalLoopProc, /* modalProc */ 92}; 93 94 95/* 96 *---------------------------------------------------------------------- 97 * 98 * TkpCreateScrollbar -- 99 * 100 * Allocate a new TkScrollbar structure. 101 * 102 * Results: 103 * Returns a newly allocated TkScrollbar structure. 104 * 105 * Side effects: 106 * Registers an event handler for the widget. 107 * 108 *---------------------------------------------------------------------- 109 */ 110 111TkScrollbar * 112TkpCreateScrollbar( 113 Tk_Window tkwin) 114{ 115 WinScrollbar *scrollPtr; 116 TkWindow *winPtr = (TkWindow *)tkwin; 117 118 if (!initialized) { 119 Tcl_MutexLock(&winScrlbrMutex); 120 UpdateScrollbarMetrics(); 121 initialized = 1; 122 Tcl_MutexUnlock(&winScrlbrMutex); 123 } 124 125 scrollPtr = (WinScrollbar *) ckalloc(sizeof(WinScrollbar)); 126 scrollPtr->winFlags = 0; 127 scrollPtr->hwnd = NULL; 128 129 Tk_CreateEventHandler(tkwin, 130 ExposureMask|StructureNotifyMask|FocusChangeMask, 131 TkScrollbarEventProc, (ClientData) scrollPtr); 132 133 if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) { 134 Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL, 135 (ClientData)1); 136 TkCreateBindingProcedure(winPtr->mainPtr->interp, 137 winPtr->mainPtr->bindingTable, 138 (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>", 139 ScrollbarBindProc, NULL, NULL); 140 } 141 142 return (TkScrollbar *) scrollPtr; 143} 144 145/* 146 *---------------------------------------------------------------------- 147 * 148 * UpdateScrollbar -- 149 * 150 * This function updates the position and size of the scrollbar thumb 151 * based on the current settings. 152 * 153 * Results: 154 * None. 155 * 156 * Side effects: 157 * Moves the thumb. 158 * 159 *---------------------------------------------------------------------- 160 */ 161 162static void 163UpdateScrollbar( 164 WinScrollbar *scrollPtr) 165{ 166 SCROLLINFO scrollInfo; 167 double thumbSize; 168 169 /* 170 * Update the current scrollbar position and shape. 171 */ 172 173 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; 174 scrollInfo.cbSize = sizeof(scrollInfo); 175 scrollInfo.nMin = 0; 176 scrollInfo.nMax = MAX_SCROLL; 177 thumbSize = (scrollPtr->info.lastFraction - scrollPtr->info.firstFraction); 178 scrollInfo.nPage = ((UINT) (thumbSize * (double) MAX_SCROLL)) + 1; 179 if (thumbSize < 1.0) { 180 scrollInfo.nPos = (int) 181 ((scrollPtr->info.firstFraction / (1.0-thumbSize)) 182 * (MAX_SCROLL - (scrollInfo.nPage - 1))); 183 } else { 184 scrollInfo.nPos = 0; 185 186 /* 187 * Disable the scrollbar when there is nothing to scroll. This is 188 * standard Windows style (see eg Notepad). Also prevents possible 189 * crash on XP+ systems [Bug #624116]. 190 */ 191 192 scrollInfo.fMask |= SIF_DISABLENOSCROLL; 193 } 194 SetScrollInfo(scrollPtr->hwnd, SB_CTL, &scrollInfo, TRUE); 195} 196 197/* 198 *---------------------------------------------------------------------- 199 * 200 * CreateProc -- 201 * 202 * This function creates a new Scrollbar control, subclasses the 203 * instance, and generates a new Window object. 204 * 205 * Results: 206 * Returns the newly allocated Window object, or None on failure. 207 * 208 * Side effects: 209 * Causes a new Scrollbar control to come into existence. 210 * 211 *---------------------------------------------------------------------- 212 */ 213 214static Window 215CreateProc( 216 Tk_Window tkwin, /* Token for window. */ 217 Window parentWin, /* Parent of new window. */ 218 ClientData instanceData) /* Scrollbar instance data. */ 219{ 220 DWORD style; 221 Window window; 222 HWND parent; 223 TkWindow *winPtr; 224 WinScrollbar *scrollPtr = (WinScrollbar *)instanceData; 225 226 parent = Tk_GetHWND(parentWin); 227 228 if (scrollPtr->info.vertical) { 229 style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS 230 | SBS_VERT | SBS_RIGHTALIGN; 231 } else { 232 style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS 233 | SBS_HORZ | SBS_BOTTOMALIGN; 234 } 235 236 scrollPtr->hwnd = CreateWindow("SCROLLBAR", NULL, style, 237 Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin), 238 parent, NULL, Tk_GetHINSTANCE(), NULL); 239 240 /* 241 * Ensure new window is inserted into the stacking order at the correct 242 * place. 243 */ 244 245 SetWindowPos(scrollPtr->hwnd, HWND_TOP, 0, 0, 0, 0, 246 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); 247 248 for (winPtr = ((TkWindow*)tkwin)->nextPtr; winPtr != NULL; 249 winPtr = winPtr->nextPtr) { 250 if ((winPtr->window != None) && !(winPtr->flags & TK_TOP_HIERARCHY)) { 251 TkWinSetWindowPos(scrollPtr->hwnd, Tk_GetHWND(winPtr->window), 252 Below); 253 break; 254 } 255 } 256 257 scrollPtr->lastVertical = scrollPtr->info.vertical; 258 scrollPtr->oldProc = (WNDPROC)SetWindowLongPtr(scrollPtr->hwnd, 259 GWLP_WNDPROC, (INT_PTR) ScrollbarProc); 260 window = Tk_AttachHWND(tkwin, scrollPtr->hwnd); 261 262 UpdateScrollbar(scrollPtr); 263 return window; 264} 265 266/* 267 *-------------------------------------------------------------- 268 * 269 * TkpDisplayScrollbar -- 270 * 271 * This procedure redraws the contents of a scrollbar window. It is 272 * invoked as a do-when-idle handler, so it only runs when there's 273 * nothing else for the application to do. 274 * 275 * Results: 276 * None. 277 * 278 * Side effects: 279 * Information appears on the screen. 280 * 281 *-------------------------------------------------------------- 282 */ 283 284void 285TkpDisplayScrollbar( 286 ClientData clientData) /* Information about window. */ 287{ 288 WinScrollbar *scrollPtr = (WinScrollbar *) clientData; 289 Tk_Window tkwin = scrollPtr->info.tkwin; 290 291 scrollPtr->info.flags &= ~REDRAW_PENDING; 292 if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) { 293 return; 294 } 295 296 /* 297 * Destroy and recreate the scrollbar control if the orientation has 298 * changed. 299 */ 300 301 if (scrollPtr->lastVertical != scrollPtr->info.vertical) { 302 HWND hwnd = Tk_GetHWND(Tk_WindowId(tkwin)); 303 304 SetWindowLongPtr(hwnd, GWLP_WNDPROC, (INT_PTR) scrollPtr->oldProc); 305 DestroyWindow(hwnd); 306 307 CreateProc(tkwin, Tk_WindowId(Tk_Parent(tkwin)), 308 (ClientData) scrollPtr); 309 } else { 310 UpdateScrollbar(scrollPtr); 311 } 312} 313 314/* 315 *---------------------------------------------------------------------- 316 * 317 * TkpDestroyScrollbar -- 318 * 319 * Free data structures associated with the scrollbar control. 320 * 321 * Results: 322 * None. 323 * 324 * Side effects: 325 * Restores the default control state. 326 * 327 *---------------------------------------------------------------------- 328 */ 329 330void 331TkpDestroyScrollbar( 332 TkScrollbar *scrollPtr) 333{ 334 WinScrollbar *winScrollPtr = (WinScrollbar *)scrollPtr; 335 HWND hwnd = winScrollPtr->hwnd; 336 337 if (hwnd) { 338 SetWindowLongPtr(hwnd, GWLP_WNDPROC, (INT_PTR) winScrollPtr->oldProc); 339 if (winScrollPtr->winFlags & IN_MODAL_LOOP) { 340 ((TkWindow *)scrollPtr->tkwin)->flags |= TK_DONT_DESTROY_WINDOW; 341 SetParent(hwnd, NULL); 342 } 343 } 344 winScrollPtr->winFlags |= ALREADY_DEAD; 345} 346 347/* 348 *---------------------------------------------------------------------- 349 * 350 * UpdateScrollbarMetrics -- 351 * 352 * This function retrieves the current system metrics for a scrollbar. 353 * 354 * Results: 355 * None. 356 * 357 * Side effects: 358 * Updates the geometry cache info for all scrollbars. 359 * 360 *---------------------------------------------------------------------- 361 */ 362 363void 364UpdateScrollbarMetrics(void) 365{ 366 Tk_ConfigSpec *specPtr; 367 368 hArrowWidth = GetSystemMetrics(SM_CXHSCROLL); 369 hThumb = GetSystemMetrics(SM_CXHTHUMB); 370 vArrowWidth = GetSystemMetrics(SM_CXVSCROLL); 371 vArrowHeight = GetSystemMetrics(SM_CYVSCROLL); 372 vThumb = GetSystemMetrics(SM_CYVTHUMB); 373 374 sprintf(defWidth, "%d", vArrowWidth); 375 for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END; 376 specPtr++) { 377 if (specPtr->offset == Tk_Offset(TkScrollbar, width)) { 378 specPtr->defValue = defWidth; 379 } 380 } 381} 382 383/* 384 *---------------------------------------------------------------------- 385 * 386 * TkpComputeScrollbarGeometry -- 387 * 388 * After changes in a scrollbar's size or configuration, this procedure 389 * recomputes various geometry information used in displaying the 390 * scrollbar. 391 * 392 * Results: 393 * None. 394 * 395 * Side effects: 396 * The scrollbar will be displayed differently. 397 * 398 *---------------------------------------------------------------------- 399 */ 400 401void 402TkpComputeScrollbarGeometry( 403 register TkScrollbar *scrollPtr) 404 /* Scrollbar whose geometry may have 405 * changed. */ 406{ 407 int fieldLength, minThumbSize; 408 409 /* 410 * Windows doesn't use focus rings on scrollbars, but we still perform 411 * basic sanity checks to appease backwards compatibility. 412 */ 413 414 if (scrollPtr->highlightWidth < 0) { 415 scrollPtr->highlightWidth = 0; 416 } 417 418 if (scrollPtr->vertical) { 419 scrollPtr->arrowLength = vArrowHeight; 420 fieldLength = Tk_Height(scrollPtr->tkwin); 421 minThumbSize = vThumb; 422 } else { 423 scrollPtr->arrowLength = hArrowWidth; 424 fieldLength = Tk_Width(scrollPtr->tkwin); 425 minThumbSize = hThumb; 426 } 427 fieldLength -= 2*scrollPtr->arrowLength; 428 if (fieldLength < 0) { 429 fieldLength = 0; 430 } 431 scrollPtr->sliderFirst = (int) ((double)fieldLength 432 * scrollPtr->firstFraction); 433 scrollPtr->sliderLast = (int) ((double)fieldLength 434 * scrollPtr->lastFraction); 435 436 /* 437 * Adjust the slider so that some piece of it is always displayed in the 438 * scrollbar and so that it has at least a minimal width (so it can be 439 * grabbed with the mouse). 440 */ 441 442 if (scrollPtr->sliderFirst > fieldLength) { 443 scrollPtr->sliderFirst = fieldLength; 444 } 445 if (scrollPtr->sliderFirst < 0) { 446 scrollPtr->sliderFirst = 0; 447 } 448 if (scrollPtr->sliderLast < (scrollPtr->sliderFirst 449 + minThumbSize)) { 450 scrollPtr->sliderLast = scrollPtr->sliderFirst + minThumbSize; 451 } 452 if (scrollPtr->sliderLast > fieldLength) { 453 scrollPtr->sliderLast = fieldLength; 454 } 455 scrollPtr->sliderFirst += scrollPtr->arrowLength; 456 scrollPtr->sliderLast += scrollPtr->arrowLength; 457 458 /* 459 * Register the desired geometry for the window (leave enough space for 460 * the two arrows plus a minimum-size slider, plus border around the whole 461 * window, if any). Then arrange for the window to be redisplayed. 462 */ 463 464 if (scrollPtr->vertical) { 465 Tk_GeometryRequest(scrollPtr->tkwin, 466 scrollPtr->width, 2*scrollPtr->arrowLength + minThumbSize); 467 } else { 468 Tk_GeometryRequest(scrollPtr->tkwin, 469 2*scrollPtr->arrowLength + minThumbSize, scrollPtr->width); 470 } 471 Tk_SetInternalBorder(scrollPtr->tkwin, 0); 472} 473 474/* 475 *---------------------------------------------------------------------- 476 * 477 * ScrollbarProc -- 478 * 479 * This function is call by Windows whenever an event occurs on a 480 * scrollbar control created by Tk. 481 * 482 * Results: 483 * Standard Windows return value. 484 * 485 * Side effects: 486 * May generate events. 487 * 488 *---------------------------------------------------------------------- 489 */ 490 491static LRESULT CALLBACK 492ScrollbarProc( 493 HWND hwnd, 494 UINT message, 495 WPARAM wParam, 496 LPARAM lParam) 497{ 498 LRESULT result; 499 POINT point; 500 WinScrollbar *scrollPtr; 501 Tk_Window tkwin = Tk_HWNDToWindow(hwnd); 502 503 if (tkwin == NULL) { 504 Tcl_Panic("ScrollbarProc called on an invalid HWND"); 505 } 506 scrollPtr = (WinScrollbar *)((TkWindow*)tkwin)->instanceData; 507 508 switch(message) { 509 case WM_HSCROLL: 510 case WM_VSCROLL: { 511 Tcl_Interp *interp; 512 Tcl_DString cmdString; 513 int command = LOWORD(wParam); 514 int code; 515 516 GetCursorPos(&point); 517 Tk_TranslateWinEvent(NULL, WM_MOUSEMOVE, 0, 518 MAKELPARAM(point.x, point.y), &result); 519 520 if (command == SB_ENDSCROLL) { 521 return 0; 522 } 523 524 /* 525 * Bail out immediately if there isn't a command to invoke. 526 */ 527 528 if (scrollPtr->info.commandSize == 0) { 529 Tcl_ServiceAll(); 530 return 0; 531 } 532 533 Tcl_DStringInit(&cmdString); 534 Tcl_DStringAppend(&cmdString, scrollPtr->info.command, 535 scrollPtr->info.commandSize); 536 537 if (command == SB_LINELEFT || command == SB_LINERIGHT) { 538 Tcl_DStringAppendElement(&cmdString, "scroll"); 539 Tcl_DStringAppendElement(&cmdString, 540 (command == SB_LINELEFT ) ? "-1" : "1"); 541 Tcl_DStringAppendElement(&cmdString, "units"); 542 } else if (command == SB_PAGELEFT || command == SB_PAGERIGHT) { 543 Tcl_DStringAppendElement(&cmdString, "scroll"); 544 Tcl_DStringAppendElement(&cmdString, 545 (command == SB_PAGELEFT ) ? "-1" : "1"); 546 Tcl_DStringAppendElement(&cmdString, "pages"); 547 } else { 548 char valueString[TCL_DOUBLE_SPACE]; 549 double pos = 0.0; 550 551 switch (command) { 552 case SB_THUMBPOSITION: 553 pos = ((double)HIWORD(wParam)) / MAX_SCROLL; 554 break; 555 case SB_THUMBTRACK: 556 pos = ((double)HIWORD(wParam)) / MAX_SCROLL; 557 break; 558 case SB_TOP: 559 pos = 0.0; 560 break; 561 case SB_BOTTOM: 562 pos = 1.0; 563 break; 564 } 565 566 Tcl_PrintDouble(NULL, pos, valueString); 567 Tcl_DStringAppendElement(&cmdString, "moveto"); 568 Tcl_DStringAppendElement(&cmdString, valueString); 569 } 570 571 interp = scrollPtr->info.interp; 572 code = Tcl_GlobalEval(interp, cmdString.string); 573 if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { 574 Tcl_AddErrorInfo(interp, "\n (scrollbar command)"); 575 Tcl_BackgroundError(interp); 576 } 577 Tcl_DStringFree(&cmdString); 578 579 Tcl_ServiceAll(); 580 return 0; 581 } 582 583 default: 584 if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) { 585 return result; 586 } 587 } 588 return CallWindowProc(scrollPtr->oldProc, hwnd, message, wParam, lParam); 589} 590 591/* 592 *---------------------------------------------------------------------- 593 * 594 * TkpConfigureScrollbar -- 595 * 596 * This procedure is called after the generic code has finished 597 * processing configuration options, in order to configure platform 598 * specific options. 599 * 600 * Results: 601 * None. 602 * 603 * Side effects: 604 * None. 605 * 606 *---------------------------------------------------------------------- 607 */ 608 609void 610TkpConfigureScrollbar( 611 register TkScrollbar *scrollPtr) 612 /* Information about widget; may or may not 613 * already have values for some fields. */ 614{ 615} 616 617/* 618 *-------------------------------------------------------------- 619 * 620 * ScrollbarBindProc -- 621 * 622 * This procedure is invoked when the default <ButtonPress> binding on 623 * the Scrollbar bind tag fires. 624 * 625 * Results: 626 * None. 627 * 628 * Side effects: 629 * The event enters a modal loop. 630 * 631 *-------------------------------------------------------------- 632 */ 633 634static int 635ScrollbarBindProc( 636 ClientData clientData, 637 Tcl_Interp *interp, 638 XEvent *eventPtr, 639 Tk_Window tkwin, 640 KeySym keySym) 641{ 642 TkWindow *winPtr = (TkWindow *) tkwin; 643 644 if (eventPtr->type == ButtonPress) { 645 winPtr->flags |= TK_DEFER_MODAL; 646 } 647 return TCL_OK; 648} 649 650/* 651 *---------------------------------------------------------------------- 652 * 653 * ModalLoopProc -- 654 * 655 * This function is invoked at the end of the event processing whenever 656 * the ScrollbarBindProc has been invoked for a ButtonPress event. 657 * 658 * Results: 659 * None. 660 * 661 * Side effects: 662 * Enters a modal loop. 663 * 664 *---------------------------------------------------------------------- 665 */ 666 667static void 668ModalLoopProc( 669 Tk_Window tkwin, 670 XEvent *eventPtr) 671{ 672 TkWindow *winPtr = (TkWindow *) tkwin; 673 WinScrollbar *scrollPtr = (WinScrollbar *) winPtr->instanceData; 674 int oldMode; 675 676 if (scrollPtr->hwnd) { 677 Tcl_Preserve(scrollPtr); 678 scrollPtr->winFlags |= IN_MODAL_LOOP; 679 oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); 680 TkWinResendEvent(scrollPtr->oldProc, scrollPtr->hwnd, eventPtr); 681 (void) Tcl_SetServiceMode(oldMode); 682 scrollPtr->winFlags &= ~IN_MODAL_LOOP; 683 if (scrollPtr->hwnd && scrollPtr->winFlags & ALREADY_DEAD) { 684 DestroyWindow(scrollPtr->hwnd); 685 } 686 Tcl_Release(scrollPtr); 687 } 688} 689 690/* 691 *-------------------------------------------------------------- 692 * 693 * TkpScrollbarPosition -- 694 * 695 * Determine the scrollbar element corresponding to a given position. 696 * 697 * Results: 698 * One of TOP_ARROW, TOP_GAP, etc., indicating which element of the 699 * scrollbar covers the position given by (x, y). If (x,y) is outside the 700 * scrollbar entirely, then OUTSIDE is returned. 701 * 702 * Side effects: 703 * None. 704 * 705 *-------------------------------------------------------------- 706 */ 707 708int 709TkpScrollbarPosition( 710 register TkScrollbar *scrollPtr, 711 /* Scrollbar widget record. */ 712 int x, int y) /* Coordinates within scrollPtr's window. */ 713{ 714 int length, width, tmp; 715 716 if (scrollPtr->vertical) { 717 length = Tk_Height(scrollPtr->tkwin); 718 width = Tk_Width(scrollPtr->tkwin); 719 } else { 720 tmp = x; 721 x = y; 722 y = tmp; 723 length = Tk_Width(scrollPtr->tkwin); 724 width = Tk_Height(scrollPtr->tkwin); 725 } 726 727 if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset)) 728 || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) { 729 return OUTSIDE; 730 } 731 732 /* 733 * All of the calculations in this procedure mirror those in 734 * TkpDisplayScrollbar. Be sure to keep the two consistent. 735 */ 736 737 if (y < (scrollPtr->inset + scrollPtr->arrowLength)) { 738 return TOP_ARROW; 739 } 740 if (y < scrollPtr->sliderFirst) { 741 return TOP_GAP; 742 } 743 if (y < scrollPtr->sliderLast) { 744 return SLIDER; 745 } 746 if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) { 747 return BOTTOM_ARROW; 748 } 749 return BOTTOM_GAP; 750} 751 752/* 753 * Local Variables: 754 * mode: c 755 * c-basic-offset: 4 756 * fill-column: 78 757 * End: 758 */ 759