tkWinScrlbr.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
源码类别:

通讯编程

开发平台:

Visual C++

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