summaryrefslogtreecommitdiffstats
path: root/win/tkWinScrlbr.c
diff options
context:
space:
mode:
authorrjohnson <rjohnson>1998-04-01 09:51:44 (GMT)
committerrjohnson <rjohnson>1998-04-01 09:51:44 (GMT)
commit066ea7fd88d49cb456f74da71dbe875e4fc0aabb (patch)
tree8fb30cb152c4dc191be47fa043d2e6f5ea38c7ba /win/tkWinScrlbr.c
parent13242623d2ff3ea02ab6a62bfb48a7dbb5c27e22 (diff)
downloadtk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.zip
tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.tar.gz
tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.tar.bz2
Initial revision
Diffstat (limited to 'win/tkWinScrlbr.c')
-rw-r--r--win/tkWinScrlbr.c745
1 files changed, 745 insertions, 0 deletions
diff --git a/win/tkWinScrlbr.c b/win/tkWinScrlbr.c
new file mode 100644
index 0000000..6c1a664
--- /dev/null
+++ b/win/tkWinScrlbr.c
@@ -0,0 +1,745 @@
+/*
+ * tkWinScrollbar.c --
+ *
+ * This file implements the Windows specific portion of the scrollbar
+ * widget.
+ *
+ * Copyright (c) 1996 by Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * SCCS: @(#) tkWinScrlbr.c 1.19 97/08/13 17:37:49
+ */
+
+#include "tkWinInt.h"
+#include "tkScrollbar.h"
+
+
+/*
+ * The following constant is used to specify the maximum scroll position.
+ * This value is limited by the Win32 API to either 16-bits or 32-bits,
+ * depending on the context. For now we'll just use a value small
+ * enough to fit in 16-bits, but which gives us 4-digits of precision.
+ */
+
+#define MAX_SCROLL 10000
+
+/*
+ * Declaration of Windows specific scrollbar structure.
+ */
+
+typedef struct WinScrollbar {
+ TkScrollbar info; /* Generic scrollbar info. */
+ WNDPROC oldProc; /* Old window procedure. */
+ int lastVertical; /* 1 if was vertical at last refresh. */
+ HWND hwnd; /* Current window handle. */
+ int winFlags; /* Various flags; see below. */
+} WinScrollbar;
+
+/*
+ * Flag bits for native scrollbars:
+ *
+ * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle
+ * of a modal loop.
+ * ALREADY_DEAD: Non-zero means this scrollbar has been
+ * destroyed, but has not been cleaned up.
+ */
+
+#define IN_MODAL_LOOP 1
+#define ALREADY_DEAD 2
+
+/*
+ * Cached system metrics used to determine scrollbar geometry.
+ */
+
+static int initialized = 0;
+static int hArrowWidth, hThumb; /* Horizontal control metrics. */
+static int vArrowWidth, vArrowHeight, vThumb; /* Vertical control metrics. */
+
+/*
+ * This variable holds the default width for a scrollbar in string
+ * form for use in a Tk_ConfigSpec.
+ */
+
+static char defWidth[8];
+
+/*
+ * Declarations for functions defined in this file.
+ */
+
+static Window CreateProc _ANSI_ARGS_((Tk_Window tkwin,
+ Window parent, ClientData instanceData));
+static void ModalLoopProc _ANSI_ARGS_((Tk_Window tkwin,
+ XEvent *eventPtr));
+static int ScrollbarBindProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, XEvent *eventPtr,
+ Tk_Window tkwin, KeySym keySym));
+static LRESULT CALLBACK ScrollbarProc _ANSI_ARGS_((HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam));
+static void UpdateScrollbar _ANSI_ARGS_((
+ WinScrollbar *scrollPtr));
+static void UpdateScrollbarMetrics _ANSI_ARGS_((void));
+
+/*
+ * The class procedure table for the scrollbar widget.
+ */
+
+TkClassProcs tkpScrollbarProcs = {
+ CreateProc, /* createProc */
+ NULL, /* geometryProc */
+ ModalLoopProc, /* modalProc */
+};
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpCreateScrollbar --
+ *
+ * Allocate a new TkScrollbar structure.
+ *
+ * Results:
+ * Returns a newly allocated TkScrollbar structure.
+ *
+ * Side effects:
+ * Registers an event handler for the widget.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TkScrollbar *
+TkpCreateScrollbar(tkwin)
+ Tk_Window tkwin;
+{
+ WinScrollbar *scrollPtr;
+ TkWindow *winPtr = (TkWindow *)tkwin;
+
+ if (!initialized) {
+ UpdateScrollbarMetrics();
+ initialized = 1;
+ }
+
+ scrollPtr = (WinScrollbar *) ckalloc(sizeof(WinScrollbar));
+ scrollPtr->winFlags = 0;
+ scrollPtr->hwnd = NULL;
+
+ Tk_CreateEventHandler(tkwin,
+ ExposureMask|StructureNotifyMask|FocusChangeMask,
+ TkScrollbarEventProc, (ClientData) scrollPtr);
+
+ if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
+ Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL,
+ (ClientData)1);
+ TkCreateBindingProcedure(winPtr->mainPtr->interp,
+ winPtr->mainPtr->bindingTable,
+ (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
+ ScrollbarBindProc, NULL, NULL);
+ }
+
+ return (TkScrollbar*) scrollPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * UpdateScrollbar --
+ *
+ * This function updates the position and size of the scrollbar
+ * thumb based on the current settings.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Moves the thumb.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+UpdateScrollbar(scrollPtr)
+ WinScrollbar *scrollPtr;
+{
+ SCROLLINFO scrollInfo;
+ double thumbSize;
+
+ /*
+ * Update the current scrollbar position and shape.
+ */
+
+ scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ scrollInfo.cbSize = sizeof(scrollInfo);
+ scrollInfo.nMin = 0;
+ scrollInfo.nMax = MAX_SCROLL;
+ thumbSize = (scrollPtr->info.lastFraction - scrollPtr->info.firstFraction);
+ if (tkpIsWin32s) {
+ scrollInfo.nPage = 0;
+ } else {
+ scrollInfo.nPage = ((UINT) (thumbSize * (double) MAX_SCROLL)) + 1;
+ }
+ if (thumbSize < 1.0) {
+ scrollInfo.nPos = (int)
+ ((scrollPtr->info.firstFraction / (1.0-thumbSize))
+ * (MAX_SCROLL - (scrollInfo.nPage - 1)));
+ } else {
+ scrollInfo.nPos = 0;
+ }
+ SetScrollInfo(scrollPtr->hwnd, SB_CTL, &scrollInfo, TRUE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateProc --
+ *
+ * This function creates a new Scrollbar control, subclasses
+ * the instance, and generates a new Window object.
+ *
+ * Results:
+ * Returns the newly allocated Window object, or None on failure.
+ *
+ * Side effects:
+ * Causes a new Scrollbar control to come into existence.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Window
+CreateProc(tkwin, parentWin, instanceData)
+ Tk_Window tkwin; /* Token for window. */
+ Window parentWin; /* Parent of new window. */
+ ClientData instanceData; /* Scrollbar instance data. */
+{
+ DWORD style;
+ Window window;
+ HWND parent;
+ TkWindow *winPtr;
+ WinScrollbar *scrollPtr = (WinScrollbar *)instanceData;
+
+ parent = Tk_GetHWND(parentWin);
+
+ if (scrollPtr->info.vertical) {
+ style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
+ | SBS_VERT | SBS_RIGHTALIGN;
+ } else {
+ style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
+ | SBS_HORZ | SBS_BOTTOMALIGN;
+ }
+
+ scrollPtr->hwnd = CreateWindow("SCROLLBAR", NULL, style,
+ Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin),
+ parent, NULL, Tk_GetHINSTANCE(), NULL);
+
+ /*
+ * Ensure new window is inserted into the stacking order at the correct
+ * place.
+ */
+
+ SetWindowPos(scrollPtr->hwnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+
+ for (winPtr = ((TkWindow*)tkwin)->nextPtr; winPtr != NULL;
+ winPtr = winPtr->nextPtr) {
+ if ((winPtr->window != None) && !(winPtr->flags & TK_TOP_LEVEL)) {
+ TkWinSetWindowPos(scrollPtr->hwnd, Tk_GetHWND(winPtr->window),
+ Below);
+ break;
+ }
+ }
+
+ scrollPtr->lastVertical = scrollPtr->info.vertical;
+ scrollPtr->oldProc = (WNDPROC)SetWindowLong(scrollPtr->hwnd, GWL_WNDPROC,
+ (DWORD) ScrollbarProc);
+ window = Tk_AttachHWND(tkwin, scrollPtr->hwnd);
+
+ UpdateScrollbar(scrollPtr);
+ return window;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkpDisplayScrollbar --
+ *
+ * This procedure redraws the contents of a scrollbar window.
+ * It is invoked as a do-when-idle handler, so it only runs
+ * when there's nothing else for the application to do.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Information appears on the screen.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkpDisplayScrollbar(clientData)
+ ClientData clientData; /* Information about window. */
+{
+ WinScrollbar *scrollPtr = (WinScrollbar *) clientData;
+ Tk_Window tkwin = scrollPtr->info.tkwin;
+
+ scrollPtr->info.flags &= ~REDRAW_PENDING;
+ if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+
+ /*
+ * Destroy and recreate the scrollbar control if the orientation
+ * has changed.
+ */
+
+ if (scrollPtr->lastVertical != scrollPtr->info.vertical) {
+ HWND hwnd = Tk_GetHWND(Tk_WindowId(tkwin));
+
+ SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) scrollPtr->oldProc);
+ DestroyWindow(hwnd);
+
+ CreateProc(tkwin, Tk_WindowId(Tk_Parent(tkwin)),
+ (ClientData) scrollPtr);
+ } else {
+ UpdateScrollbar(scrollPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDestroyScrollbar --
+ *
+ * Free data structures associated with the scrollbar control.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Restores the default control state.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyScrollbar(scrollPtr)
+ TkScrollbar *scrollPtr;
+{
+ WinScrollbar *winScrollPtr = (WinScrollbar *)scrollPtr;
+ HWND hwnd = winScrollPtr->hwnd;
+ if (hwnd) {
+ SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) winScrollPtr->oldProc);
+ if (winScrollPtr->winFlags & IN_MODAL_LOOP) {
+ ((TkWindow *)scrollPtr->tkwin)->flags |= TK_DONT_DESTROY_WINDOW;
+ SetParent(hwnd, NULL);
+ }
+ }
+ winScrollPtr->winFlags |= ALREADY_DEAD;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * UpdateScrollbarMetrics --
+ *
+ * This function retrieves the current system metrics for a
+ * scrollbar.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Updates the geometry cache info for all scrollbars.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+UpdateScrollbarMetrics()
+{
+ Tk_ConfigSpec *specPtr;
+
+ hArrowWidth = GetSystemMetrics(SM_CXHSCROLL);
+ hThumb = GetSystemMetrics(SM_CXHTHUMB);
+ vArrowWidth = GetSystemMetrics(SM_CXVSCROLL);
+ vArrowHeight = GetSystemMetrics(SM_CYVSCROLL);
+ vThumb = GetSystemMetrics(SM_CYVTHUMB);
+
+ sprintf(defWidth, "%d", vArrowWidth);
+ for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END;
+ specPtr++) {
+ if (specPtr->offset == Tk_Offset(TkScrollbar, width)) {
+ specPtr->defValue = defWidth;
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpComputeScrollbarGeometry --
+ *
+ * After changes in a scrollbar's size or configuration, this
+ * procedure recomputes various geometry information used in
+ * displaying the scrollbar.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The scrollbar will be displayed differently.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpComputeScrollbarGeometry(scrollPtr)
+ register TkScrollbar *scrollPtr; /* Scrollbar whose geometry may
+ * have changed. */
+{
+ int fieldLength, minThumbSize;
+
+ /*
+ * Windows doesn't use focus rings on scrollbars, but we still
+ * perform basic sanity checks to appease backwards compatibility.
+ */
+
+ if (scrollPtr->highlightWidth < 0) {
+ scrollPtr->highlightWidth = 0;
+ }
+
+ if (scrollPtr->vertical) {
+ scrollPtr->arrowLength = vArrowHeight;
+ fieldLength = Tk_Height(scrollPtr->tkwin);
+ minThumbSize = vThumb;
+ } else {
+ scrollPtr->arrowLength = hArrowWidth;
+ fieldLength = Tk_Width(scrollPtr->tkwin);
+ minThumbSize = hThumb;
+ }
+ fieldLength -= 2*scrollPtr->arrowLength;
+ if (fieldLength < 0) {
+ fieldLength = 0;
+ }
+ scrollPtr->sliderFirst = (int) ((double)fieldLength
+ * scrollPtr->firstFraction);
+ scrollPtr->sliderLast = (int) ((double)fieldLength
+ * scrollPtr->lastFraction);
+
+ /*
+ * Adjust the slider so that some piece of it is always
+ * displayed in the scrollbar and so that it has at least
+ * a minimal width (so it can be grabbed with the mouse).
+ */
+
+ if (scrollPtr->sliderFirst > fieldLength) {
+ scrollPtr->sliderFirst = fieldLength;
+ }
+ if (scrollPtr->sliderFirst < 0) {
+ scrollPtr->sliderFirst = 0;
+ }
+ if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
+ + minThumbSize)) {
+ scrollPtr->sliderLast = scrollPtr->sliderFirst + minThumbSize;
+ }
+ if (scrollPtr->sliderLast > fieldLength) {
+ scrollPtr->sliderLast = fieldLength;
+ }
+ scrollPtr->sliderFirst += scrollPtr->arrowLength;
+ scrollPtr->sliderLast += scrollPtr->arrowLength;
+
+ /*
+ * Register the desired geometry for the window (leave enough space
+ * for the two arrows plus a minimum-size slider, plus border around
+ * the whole window, if any). Then arrange for the window to be
+ * redisplayed.
+ */
+
+ if (scrollPtr->vertical) {
+ Tk_GeometryRequest(scrollPtr->tkwin,
+ scrollPtr->width, 2*scrollPtr->arrowLength + minThumbSize);
+ } else {
+ Tk_GeometryRequest(scrollPtr->tkwin,
+ 2*scrollPtr->arrowLength + minThumbSize, scrollPtr->width);
+ }
+ Tk_SetInternalBorder(scrollPtr->tkwin, 0);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ScrollbarProc --
+ *
+ * This function is call by Windows whenever an event occurs on
+ * a scrollbar control created by Tk.
+ *
+ * Results:
+ * Standard Windows return value.
+ *
+ * Side effects:
+ * May generate events.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static LRESULT CALLBACK
+ScrollbarProc(hwnd, message, wParam, lParam)
+ HWND hwnd;
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+{
+ LRESULT result;
+ POINT point;
+ WinScrollbar *scrollPtr;
+ Tk_Window tkwin = Tk_HWNDToWindow(hwnd);
+
+ if (tkwin == NULL) {
+ panic("ScrollbarProc called on an invalid HWND");
+ }
+ scrollPtr = (WinScrollbar *)((TkWindow*)tkwin)->instanceData;
+
+ switch(message) {
+ case WM_HSCROLL:
+ case WM_VSCROLL: {
+ Tcl_Interp *interp;
+ Tcl_DString cmdString;
+ int command = LOWORD(wParam);
+ int code;
+
+ GetCursorPos(&point);
+ Tk_TranslateWinEvent(NULL, WM_MOUSEMOVE, 0,
+ MAKELPARAM(point.x, point.y), &result);
+
+ if (command == SB_ENDSCROLL) {
+ return 0;
+ }
+
+ /*
+ * Bail out immediately if there isn't a command to invoke.
+ */
+
+ if (scrollPtr->info.commandSize == 0) {
+ Tcl_ServiceAll();
+ return 0;
+ }
+
+ Tcl_DStringInit(&cmdString);
+ Tcl_DStringAppend(&cmdString, scrollPtr->info.command,
+ scrollPtr->info.commandSize);
+
+ if (command == SB_LINELEFT || command == SB_LINERIGHT) {
+ Tcl_DStringAppendElement(&cmdString, "scroll");
+ Tcl_DStringAppendElement(&cmdString,
+ (command == SB_LINELEFT ) ? "-1" : "1");
+ Tcl_DStringAppendElement(&cmdString, "units");
+ } else if (command == SB_PAGELEFT || command == SB_PAGERIGHT) {
+ Tcl_DStringAppendElement(&cmdString, "scroll");
+ Tcl_DStringAppendElement(&cmdString,
+ (command == SB_PAGELEFT ) ? "-1" : "1");
+ Tcl_DStringAppendElement(&cmdString, "pages");
+ } else {
+ char valueString[TCL_DOUBLE_SPACE];
+ double pos = 0.0;
+ switch (command) {
+ case SB_THUMBPOSITION:
+ pos = ((double)HIWORD(wParam)) / MAX_SCROLL;
+ break;
+
+ case SB_THUMBTRACK:
+ pos = ((double)HIWORD(wParam)) / MAX_SCROLL;
+ break;
+
+ case SB_TOP:
+ pos = 0.0;
+ break;
+
+ case SB_BOTTOM:
+ pos = 1.0;
+ break;
+ }
+ sprintf(valueString, "%g", pos);
+ Tcl_DStringAppendElement(&cmdString, "moveto");
+ Tcl_DStringAppendElement(&cmdString, valueString);
+ }
+
+ interp = scrollPtr->info.interp;
+ code = Tcl_GlobalEval(interp, cmdString.string);
+ if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) {
+ Tcl_AddErrorInfo(interp, "\n (scrollbar command)");
+ Tcl_BackgroundError(interp);
+ }
+ Tcl_DStringFree(&cmdString);
+
+ Tcl_ServiceAll();
+ return 0;
+ }
+
+ default:
+ if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) {
+ return result;
+ }
+ }
+ return CallWindowProc(scrollPtr->oldProc, hwnd, message, wParam, lParam);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpConfigureScrollbar --
+ *
+ * This procedure is called after the generic code has finished
+ * processing configuration options, in order to configure
+ * platform specific options.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpConfigureScrollbar(scrollPtr)
+ register TkScrollbar *scrollPtr; /* Information about widget; may or
+ * may not already have values for
+ * some fields. */
+{
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ScrollbarBindProc --
+ *
+ * This procedure is invoked when the default <ButtonPress>
+ * binding on the Scrollbar bind tag fires.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The event enters a modal loop.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ScrollbarBindProc(clientData, interp, eventPtr, tkwin, keySym)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ XEvent *eventPtr;
+ Tk_Window tkwin;
+ KeySym keySym;
+{
+ TkWindow *winPtr = (TkWindow*)tkwin;
+ if (eventPtr->type == ButtonPress) {
+ winPtr->flags |= TK_DEFER_MODAL;
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ModalLoopProc --
+ *
+ * This function is invoked at the end of the event processing
+ * whenever the ScrollbarBindProc has been invoked for a ButtonPress
+ * event.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Enters a modal loop.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ModalLoopProc(tkwin, eventPtr)
+ Tk_Window tkwin;
+ XEvent *eventPtr;
+{
+ TkWindow *winPtr = (TkWindow*)tkwin;
+ WinScrollbar *scrollPtr = (WinScrollbar *) winPtr->instanceData;
+ int oldMode;
+
+ Tcl_Preserve((ClientData)scrollPtr);
+ scrollPtr->winFlags |= IN_MODAL_LOOP;
+ oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
+ TkWinResendEvent(scrollPtr->oldProc, scrollPtr->hwnd, eventPtr);
+ (void) Tcl_SetServiceMode(oldMode);
+ scrollPtr->winFlags &= ~IN_MODAL_LOOP;
+ if (scrollPtr->hwnd && scrollPtr->winFlags & ALREADY_DEAD) {
+ DestroyWindow(scrollPtr->hwnd);
+ }
+ Tcl_Release((ClientData)scrollPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkpScrollbarPosition --
+ *
+ * Determine the scrollbar element corresponding to a
+ * given position.
+ *
+ * Results:
+ * One of TOP_ARROW, TOP_GAP, etc., indicating which element
+ * of the scrollbar covers the position given by (x, y). If
+ * (x,y) is outside the scrollbar entirely, then OUTSIDE is
+ * returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+TkpScrollbarPosition(scrollPtr, x, y)
+ register TkScrollbar *scrollPtr; /* Scrollbar widget record. */
+ int x, y; /* Coordinates within scrollPtr's
+ * window. */
+{
+ int length, width, tmp;
+
+ if (scrollPtr->vertical) {
+ length = Tk_Height(scrollPtr->tkwin);
+ width = Tk_Width(scrollPtr->tkwin);
+ } else {
+ tmp = x;
+ x = y;
+ y = tmp;
+ length = Tk_Width(scrollPtr->tkwin);
+ width = Tk_Height(scrollPtr->tkwin);
+ }
+
+ if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
+ || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
+ return OUTSIDE;
+ }
+
+ /*
+ * All of the calculations in this procedure mirror those in
+ * TkpDisplayScrollbar. Be sure to keep the two consistent.
+ */
+
+ if (y < (scrollPtr->inset + scrollPtr->arrowLength)) {
+ return TOP_ARROW;
+ }
+ if (y < scrollPtr->sliderFirst) {
+ return TOP_GAP;
+ }
+ if (y < scrollPtr->sliderLast) {
+ return SLIDER;
+ }
+ if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) {
+ return BOTTOM_ARROW;
+ }
+ return BOTTOM_GAP;
+}