home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tk8.0.5 / os2 / tkOS2Scrlbr.c < prev    next >
C/C++ Source or Header  |  2000-06-27  |  26KB  |  912 lines

  1. /* 
  2.  * tkOS2Scrollbar.c --
  3.  *
  4.  *    This file implements the OS/2 specific portion of the scrollbar
  5.  *    widget.
  6.  *
  7.  * Copyright (c) 1999-2000 by Illya Vaes
  8.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  */
  14.  
  15. #include "tkOS2Int.h"
  16. #include "tkScrollbar.h"
  17.  
  18.  
  19. /*
  20.  * The following constant is used to specify the maximum scroll position.
  21.  * This value is limited by the PM API to a SHORT, which is 2 bytes and
  22.  * signed -> from -32768 through 32767.
  23.  * However, for compatibility/uniformity of behaviour with the Windows
  24.  * version, we use the same number here as the one there, which is chosen
  25.  * as "a value small enough to fit in 16-bits, but which gives us 4-digits
  26.  * of precision".
  27.  */
  28.  
  29. #define MAX_SCROLL 10000
  30.  
  31. /*
  32.  * Declaration of OS/2 specific scrollbar structure.
  33.  */
  34.  
  35. typedef struct OS2Scrollbar {
  36.     TkScrollbar info;        /* Generic scrollbar info. */
  37.     PFNWP oldProc;        /* Old window procedure. */
  38.     int lastVertical;        /* 1 if was vertical at last refresh. */
  39.     HWND hwnd;            /* Current window handle. */
  40.     int os2Flags;        /* Various flags; see below. */
  41. } OS2Scrollbar;
  42.  
  43. /*
  44.  * Flag bits for native scrollbars:
  45.  * 
  46.  * IN_MODAL_LOOP:        Non-zero means this scrollbar is in the middle
  47.  *                of a modal loop.
  48.  * ALREADY_DEAD:        Non-zero means this scrollbar has been
  49.  *                destroyed, but has not been cleaned up.
  50.  */
  51.  
  52. #define IN_MODAL_LOOP    1
  53. #define ALREADY_DEAD    2
  54.  
  55. /*
  56.  * Cached system metrics used to determine scrollbar geometry.
  57.  */
  58.  
  59. static int initialized = 0;
  60. static int hArrowWidth, hThumb; /* Horizontal control metrics. */
  61. static int vArrowWidth, vArrowHeight, vThumb; /* Vertical control metrics. */
  62.  
  63. /*
  64.  * This variable holds the default width for a scrollbar in string
  65.  * form for use in a Tk_ConfigSpec.
  66.  */
  67.  
  68. static char defWidth[8];
  69.  
  70. /*
  71.  * Declarations for functions defined in this file.
  72.  */
  73.  
  74. static Window        CreateProc _ANSI_ARGS_((Tk_Window tkwin,
  75.                 Window parent, ClientData instanceData));
  76. static void        ModalLoopProc _ANSI_ARGS_((Tk_Window tkwin,
  77.                 XEvent *eventPtr));
  78. static int        ScrollbarBindProc _ANSI_ARGS_((ClientData clientData,
  79.                 Tcl_Interp *interp, XEvent *eventPtr,
  80.                 Tk_Window tkwin, KeySym keySym));
  81. static MRESULT EXPENTRY    ScrollbarProc _ANSI_ARGS_((HWND hwnd, ULONG message,
  82.                 MPARAM param1, MPARAM param2));
  83. static void        UpdateScrollbar _ANSI_ARGS_((
  84.                     OS2Scrollbar *scrollPtr));
  85. static void        UpdateScrollbarMetrics _ANSI_ARGS_((void));
  86.  
  87. /*
  88.  * The class procedure table for the scrollbar widget.
  89.  */
  90.  
  91. TkClassProcs tkpScrollbarProcs = {
  92.     CreateProc,            /* createProc */
  93.     NULL,            /* geometryProc */
  94.     ModalLoopProc,        /* modalProc */
  95. };
  96.  
  97.  
  98. /*
  99.  *----------------------------------------------------------------------
  100.  *
  101.  * TkpCreateScrollbar --
  102.  *
  103.  *    Allocate a new TkScrollbar structure.
  104.  *
  105.  * Results:
  106.  *    Returns a newly allocated TkScrollbar structure.
  107.  *
  108.  * Side effects:
  109.  *    Registers an event handler for the widget.
  110.  *
  111.  *----------------------------------------------------------------------
  112.  */
  113.  
  114. TkScrollbar *
  115. TkpCreateScrollbar(tkwin)
  116.     Tk_Window tkwin;
  117. {
  118.     OS2Scrollbar *scrollPtr;
  119.     TkWindow *winPtr = (TkWindow *)tkwin;
  120.  
  121. #ifdef VERBOSE
  122.     printf("TkpCreateScrollbar\n");
  123. #endif
  124.     
  125.     if (!initialized) {
  126.     UpdateScrollbarMetrics();
  127.     initialized = 1;
  128.     }
  129.  
  130.     scrollPtr = (OS2Scrollbar *) ckalloc(sizeof(OS2Scrollbar));
  131.     scrollPtr->os2Flags = 0;
  132.     scrollPtr->hwnd = NULLHANDLE;
  133.  
  134.     Tk_CreateEventHandler(tkwin,
  135.         ExposureMask|StructureNotifyMask|FocusChangeMask,
  136.         TkScrollbarEventProc, (ClientData) scrollPtr);
  137.  
  138.     if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
  139.     Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL,
  140.         (ClientData)1);
  141.     TkCreateBindingProcedure(winPtr->mainPtr->interp,
  142.         winPtr->mainPtr->bindingTable,
  143.         (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
  144.         ScrollbarBindProc, NULL, NULL);
  145.     }
  146.  
  147.     return (TkScrollbar*) scrollPtr;
  148. }
  149.  
  150. /*
  151.  *----------------------------------------------------------------------
  152.  *
  153.  * UpdateScrollbar --
  154.  *
  155.  *    This function updates the position and size of the scrollbar
  156.  *    thumb based on the current settings.
  157.  *
  158.  * Results:
  159.  *    None.
  160.  *
  161.  * Side effects:
  162.  *    Moves the thumb.
  163.  *
  164.  *----------------------------------------------------------------------
  165.  */
  166.  
  167. static void
  168. UpdateScrollbar(scrollPtr)
  169.     OS2Scrollbar *scrollPtr;
  170. {
  171.     SHORT posFirst, posLast, posThumb, cVisible, cTotal;
  172.     double thumbSize;
  173.  
  174. #ifdef VERBOSE
  175.     printf("UpdateScrollbar, firstFraction %f, lastFraction %f\n",
  176.            scrollPtr->info.firstFraction, scrollPtr->info.lastFraction);
  177. #endif
  178.  
  179.     /*
  180.      * Update the current scrollbar position and shape.
  181.      */
  182.  
  183.     posFirst = 0;
  184.     posLast = MAX_SCROLL;
  185.     /*
  186.      * cVisible and cTotal determine OS/2's thumbsize,
  187.      * use MAX_SCROLL for cTotal
  188.      */
  189.     thumbSize = (scrollPtr->info.lastFraction - scrollPtr->info.firstFraction);
  190.     cVisible = (SHORT) (thumbSize * (double) MAX_SCROLL) + 1;
  191.     cTotal = MAX_SCROLL;
  192.     if (thumbSize < 1.0) {
  193.     posThumb = (SHORT) ((scrollPtr->info.firstFraction / (1.0-thumbSize))
  194.             * (double)cTotal);
  195.     } else {
  196.     posThumb = 0;
  197.     }
  198. #ifdef VERBOSE
  199.     printf("UpdateScrollbar sPtr %x, posThumb %d, thumbSize %f, cVisible %d\n",
  200.            scrollPtr, posThumb, thumbSize, cVisible);
  201. #endif
  202.     /* Set scrollbar range (param2) and slider position (param1) */
  203.     rc = (LONG) WinSendMsg(scrollPtr->hwnd, SBM_SETSCROLLBAR,
  204.                            MPFROMSHORT(posThumb),
  205.                            MPFROM2SHORT(posFirst, posLast));
  206. #ifdef VERBOSE
  207.     printf("    SBM_SETSCROLLBAR %s (th %d, f %d, l %d), now pos %d\n",
  208.            rc==TRUE ? "OK" : "ERROR", posThumb, posFirst, posLast,
  209.            WinSendMsg(scrollPtr->hwnd, SBM_QUERYPOS, MPVOID, MPVOID));
  210. #endif
  211.     /* Set scrollbar thumb size */
  212.     rc = (LONG) WinSendMsg(scrollPtr->hwnd, SBM_SETTHUMBSIZE,
  213.                            MPFROM2SHORT(cVisible, cTotal), MPVOID);
  214. #ifdef VERBOSE
  215.     printf("    SBM_SETTHUMBSIZE %s\n", rc==TRUE ? "OK" : "ERROR");
  216. #endif
  217. }
  218.  
  219. /*
  220.  *----------------------------------------------------------------------
  221.  *
  222.  * CreateProc --
  223.  *
  224.  *    This function creates a new Scrollbar control, subclasses
  225.  *    the instance, and generates a new Window object.
  226.  *
  227.  * Results:
  228.  *    Returns the newly allocated Window object, or None on failure.
  229.  *
  230.  * Side effects:
  231.  *    Causes a new Scrollbar control to come into existence.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235.  
  236. static Window
  237. CreateProc(tkwin, parentWin, instanceData)
  238.     Tk_Window tkwin;        /* Token for window. */
  239.     Window parentWin;        /* Parent of new window. */
  240.     ClientData instanceData;    /* Scrollbar instance data. */
  241. {
  242.     ULONG style, id;
  243.     Window window;
  244.     HWND parent;
  245.     TkWindow *winPtr;
  246.     OS2Scrollbar *scrollPtr = (OS2Scrollbar *)instanceData;
  247.  
  248. #ifdef VERBOSE
  249.     printf("CreateProc\n");
  250. #endif
  251.  
  252.     parent = Tk_GetHWND(parentWin);
  253.  
  254.     if (scrollPtr->info.vertical) {
  255.     id = FID_VERTSCROLL;
  256.     style = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
  257.             | SBS_AUTOTRACK | SBS_VERT;
  258.     } else {
  259.     id = FID_HORZSCROLL;
  260.     style = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
  261.             | SBS_AUTOTRACK | SBS_HORZ;
  262.     }
  263.  
  264.     scrollPtr->hwnd = WinCreateWindow(parent, WC_SCROLLBAR, "SCROLLBAR", style,
  265.                                       Tk_X(tkwin),
  266.                       TkOS2HwndHeight(parent) -
  267.                           (Tk_Y(tkwin) + Tk_Height(tkwin)),
  268.                       Tk_Width(tkwin), Tk_Height(tkwin),
  269.                       parent, HWND_TOP, id, NULL, NULL);
  270.     if (scrollPtr->hwnd == NULLHANDLE) {
  271.         scrollPtr->oldProc = WinDefWindowProc;
  272. #ifdef VERBOSE
  273.         printf("WinCreateWindow scrlbr %x, par %x: (%d,%d) %dx%d ERROR %x\n",
  274.                scrollPtr->hwnd, parent, Tk_X(tkwin),
  275.            TkOS2HwndHeight(parent) - (Tk_Y(tkwin) + Tk_Height(tkwin)),
  276.            Tk_Width(tkwin), Tk_Height(tkwin),
  277.                WinGetLastError(TclOS2GetHAB()));
  278. #endif
  279.         return None;
  280. #ifdef VERBOSE
  281.     } else {
  282.         printf("WinCreateWindow scrlbr %x, par %x: (%d,%d) %dx%d (%d-%d-%d)\n",
  283.                scrollPtr->hwnd, parent, Tk_X(tkwin),
  284.            TkOS2HwndHeight(parent) - (Tk_Y(tkwin) + Tk_Height(tkwin)),
  285.            Tk_Width(tkwin), Tk_Height(tkwin), TkOS2HwndHeight(parent),
  286.            Tk_Y(tkwin), Tk_Height(tkwin));
  287. #endif
  288.     }
  289.  
  290.     /*
  291.      * Ensure new window is inserted into the stacking order at the correct
  292.      * place. 
  293.      */
  294.  
  295.     for (winPtr = ((TkWindow*)tkwin)->nextPtr; winPtr != NULL;
  296.      winPtr = winPtr->nextPtr) {
  297.     if ((winPtr->window != None) && !(winPtr->flags & TK_TOP_LEVEL)) {
  298.         TkOS2SetWindowPos(scrollPtr->hwnd, Tk_GetHWND(winPtr->window),
  299.             Below);
  300.         break;
  301.     }
  302.     }
  303.  
  304.     scrollPtr->lastVertical = scrollPtr->info.vertical;
  305.     scrollPtr->oldProc = WinSubclassWindow(scrollPtr->hwnd, ScrollbarProc);
  306.     window = Tk_AttachHWND(tkwin, scrollPtr->hwnd);
  307.  
  308.     UpdateScrollbar(scrollPtr);
  309.     return window;
  310. }
  311.  
  312. /*
  313.  *--------------------------------------------------------------
  314.  *
  315.  * TkpDisplayScrollbar --
  316.  *
  317.  *    This procedure redraws the contents of a scrollbar window.
  318.  *    It is invoked as a do-when-idle handler, so it only runs
  319.  *    when there's nothing else for the application to do.
  320.  *
  321.  * Results:
  322.  *    None.
  323.  *
  324.  * Side effects:
  325.  *    Information appears on the screen.
  326.  *
  327.  *--------------------------------------------------------------
  328.  */
  329.  
  330. void
  331. TkpDisplayScrollbar(clientData)
  332.     ClientData clientData;    /* Information about window. */
  333. {
  334.     OS2Scrollbar *scrollPtr = (OS2Scrollbar *) clientData;
  335.     Tk_Window tkwin = scrollPtr->info.tkwin;
  336.  
  337. #ifdef VERBOSE
  338.     printf("TkpDisplayScrollbar\n");
  339. #endif
  340.  
  341.     scrollPtr->info.flags &= ~REDRAW_PENDING;
  342.     if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  343.     return;
  344.     }
  345.  
  346.     /*
  347.      * Destroy and recreate the scrollbar control if the orientation
  348.      * has changed.
  349.      */
  350.  
  351.     if (scrollPtr->lastVertical != scrollPtr->info.vertical) {
  352.     HWND hwnd = Tk_GetHWND(Tk_WindowId(tkwin));
  353.  
  354.     WinDestroyWindow(hwnd);
  355.  
  356.     CreateProc(tkwin, Tk_WindowId(Tk_Parent(tkwin)),
  357.         (ClientData) scrollPtr);
  358.     } else {
  359.     UpdateScrollbar(scrollPtr);
  360.     }
  361. }
  362.  
  363. /*
  364.  *----------------------------------------------------------------------
  365.  *
  366.  * TkpDestroyScrollbar --
  367.  *
  368.  *    Free data structures associated with the scrollbar control.
  369.  *
  370.  * Results:
  371.  *    None.
  372.  *
  373.  * Side effects:
  374.  *    Restores the default control state.
  375.  *
  376.  *----------------------------------------------------------------------
  377.  */
  378.  
  379. void
  380. TkpDestroyScrollbar(scrollPtr)
  381.     TkScrollbar *scrollPtr;
  382. {
  383.     OS2Scrollbar *winScrollPtr = (OS2Scrollbar *)scrollPtr;
  384.     HWND hwnd = winScrollPtr->hwnd;
  385.  
  386. #ifdef VERBOSE
  387.     printf("TkpDestroyScrollbar\n");
  388. #endif
  389.     if (hwnd) {
  390.     if (winScrollPtr->os2Flags & IN_MODAL_LOOP) {
  391.         ((TkWindow *)scrollPtr->tkwin)->flags |= TK_DONT_DESTROY_WINDOW;
  392.         WinSetParent(hwnd, HWND_DESKTOP, FALSE);
  393.         WinSetOwner(hwnd, NULLHANDLE);
  394.     }
  395.     }
  396.     winScrollPtr->os2Flags |= ALREADY_DEAD;
  397.     /* Reset lastWinPtr etc. */
  398.     TkPointerDeadWindow((TkWindow *)scrollPtr->tkwin);
  399. }
  400.  
  401. /*
  402.  *----------------------------------------------------------------------
  403.  *
  404.  * UpdateScrollbarMetrics --
  405.  *
  406.  *    This function retrieves the current system metrics for a
  407.  *    scrollbar.
  408.  *
  409.  * Results:
  410.  *    None.
  411.  *
  412.  * Side effects:
  413.  *    Updates the geometry cache info for all scrollbars.
  414.  *
  415.  *----------------------------------------------------------------------
  416.  */
  417.  
  418. void
  419. UpdateScrollbarMetrics()
  420. {
  421.     Tk_ConfigSpec *specPtr;
  422.  
  423. #ifdef VERBOSE
  424.     printf("UpdateScrollbarMetrics\n");
  425. #endif
  426.  
  427.     hArrowWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXHSCROLLARROW);
  428.     hThumb = WinQuerySysValue(HWND_DESKTOP, SV_CXHSLIDER);
  429.     vArrowWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  430.     vArrowHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYVSCROLLARROW);
  431.     vThumb = WinQuerySysValue(HWND_DESKTOP, SV_CYVSLIDER);
  432.  
  433.     sprintf(defWidth, "%d", vArrowWidth);
  434.     for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END;
  435.         specPtr++) {
  436.     if (specPtr->offset == Tk_Offset(TkScrollbar, width)) {
  437.         specPtr->defValue = defWidth;
  438.     }
  439.     }
  440. }
  441.  
  442. /*
  443.  *----------------------------------------------------------------------
  444.  *
  445.  * TkpComputeScrollbarGeometry --
  446.  *
  447.  *    After changes in a scrollbar's size or configuration, this
  448.  *    procedure recomputes various geometry information used in
  449.  *    displaying the scrollbar.
  450.  *
  451.  * Results:
  452.  *    None.
  453.  *
  454.  * Side effects:
  455.  *    The scrollbar will be displayed differently.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459.  
  460. void
  461. TkpComputeScrollbarGeometry(scrollPtr)
  462.     register TkScrollbar *scrollPtr;    /* Scrollbar whose geometry may
  463.                      * have changed. */
  464. {
  465.     int fieldLength, minThumbSize;
  466.  
  467. #ifdef VERBOSE
  468.     printf("TkpComputeScrollbarGeometry\n");
  469. #endif
  470.  
  471.     /*
  472.      * OS/2 doesn't use focus rings on scrollbars, but we still
  473.      * perform basic sanity checks to appease backwards compatibility.
  474.      */
  475.  
  476.     if (scrollPtr->highlightWidth < 0) {
  477.     scrollPtr->highlightWidth = 0;
  478.     }
  479.  
  480.     if (scrollPtr->vertical) {
  481.     scrollPtr->arrowLength = vArrowHeight;
  482.     fieldLength = Tk_Height(scrollPtr->tkwin);
  483.     minThumbSize = vThumb;
  484.     } else {
  485.     scrollPtr->arrowLength = hArrowWidth;
  486.     fieldLength = Tk_Width(scrollPtr->tkwin);
  487.     minThumbSize = hThumb;
  488.     }
  489.     fieldLength -= 2*scrollPtr->arrowLength;
  490.     if (fieldLength < 0) {
  491.     fieldLength = 0;
  492.     }
  493.     scrollPtr->sliderFirst = (int) ((double)fieldLength
  494.         * scrollPtr->firstFraction);
  495.     scrollPtr->sliderLast = (int) ((double)fieldLength
  496.         * scrollPtr->lastFraction);
  497.  
  498.     /*
  499.      * Adjust the slider so that some piece of it is always
  500.      * displayed in the scrollbar and so that it has at least
  501.      * a minimal width (so it can be grabbed with the mouse).
  502.      */
  503.  
  504.     if (scrollPtr->sliderFirst > fieldLength) {
  505.     scrollPtr->sliderFirst = fieldLength;
  506.     }
  507.     if (scrollPtr->sliderFirst < 0) {
  508.     scrollPtr->sliderFirst = 0;
  509.     }
  510.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  511.         + minThumbSize)) {
  512.     scrollPtr->sliderLast = scrollPtr->sliderFirst + minThumbSize;
  513.     }
  514.     if (scrollPtr->sliderLast > fieldLength) {
  515.     scrollPtr->sliderLast = fieldLength;
  516.     }
  517.     scrollPtr->sliderFirst += scrollPtr->arrowLength;
  518.     scrollPtr->sliderLast += scrollPtr->arrowLength;
  519.  
  520.     /*
  521.      * Register the desired geometry for the window (leave enough space
  522.      * for the two arrows plus a minimum-size slider, plus border around
  523.      * the whole window, if any).  Then arrange for the window to be
  524.      * redisplayed.
  525.      */
  526.  
  527.     if (scrollPtr->vertical) {
  528.     Tk_GeometryRequest(scrollPtr->tkwin,
  529.         scrollPtr->width, 2*scrollPtr->arrowLength + minThumbSize);
  530.     } else {
  531.     Tk_GeometryRequest(scrollPtr->tkwin,
  532.         2*scrollPtr->arrowLength + minThumbSize, scrollPtr->width);
  533.     }
  534.     Tk_SetInternalBorder(scrollPtr->tkwin, 0);
  535. }
  536.  
  537. /*
  538.  *----------------------------------------------------------------------
  539.  *
  540.  * ScrollbarProc --
  541.  *
  542.  *    This function is called by OS/2 PM whenever an event occurs on
  543.  *    a scrollbar control created by Tk.
  544.  *
  545.  * Results:
  546.  *    Standard OS/2 PM return value.
  547.  *
  548.  * Side effects:
  549.  *    May generate events.
  550.  *
  551.  *----------------------------------------------------------------------
  552.  */
  553.  
  554. static MRESULT EXPENTRY
  555. ScrollbarProc(hwnd, message, param1, param2)
  556.     HWND hwnd;
  557.     ULONG message;
  558.     MPARAM param1;
  559.     MPARAM param2;
  560. {
  561.     MRESULT result;
  562.     POINTL point;
  563.     OS2Scrollbar *scrollPtr;
  564.     Tk_Window tkwin = Tk_HWNDToWindow(hwnd);
  565.  
  566. #ifdef VERBOSE
  567.     printf("ScrollbarProc hwnd %x (tkwin %x), msg %x, p1 %x, p2 %x, owner %x\n",
  568.            hwnd, tkwin, message, param1, param2, WinQueryWindow(hwnd,QW_OWNER));
  569.     fflush(stdout);
  570. #endif
  571.  
  572.     /*
  573.      * tkwin can be NULL for WM_DESTROY due to the order of messages
  574.      * In that case use WinDefWindowProc.
  575.      */
  576.     if (tkwin == NULL) {
  577. #ifdef VERBOSE
  578.         printf("ScrollbarProc: WM_DESTROY\n");
  579. #endif
  580.         return WinDefWindowProc(hwnd, message, param1, param2);
  581.     }
  582.     if (tkwin == NULL) {
  583. #ifdef VERBOSE
  584.         printf("panicking...\n");
  585.         fflush(stdout);
  586. #endif
  587.     panic("ScrollbarProc called on an invalid HWND");
  588.     }
  589.     scrollPtr = (OS2Scrollbar *)((TkWindow*)tkwin)->instanceData;
  590.  
  591.     switch(message) {
  592.     case WM_HSCROLL:
  593.     case WM_VSCROLL: {
  594.  
  595.             /*
  596.              * param1: USHORT control identity
  597.              * param2: SHORT slider position,
  598.              *               0: either operator is not moving slider with
  599.              *                  pointer, or (where uscmd==SB_SLIDERPOSITION)
  600.              *                  pointer outside tracking rectangle when button
  601.              *                  is released.
  602.              *         USHORT command (SB_LINEUP, SB_LINEDOWN, SB_PAGEUP,
  603.              *                         SB_PAGEDOWN, SB_LINELEFT, SB_LINERIGHT,
  604.              *                         SB_PAGELEFT, SB_PAGERIGHT,
  605.              *                         SB_SLIDERPOSITION, SB_SLIDERTRACK,
  606.              *                         SB_ENDSCROLL)
  607.              */
  608.  
  609.         Tcl_Interp *interp;
  610.         Tcl_DString cmdString;
  611.         USHORT command = SHORT2FROMMP(param2);
  612.         int code;
  613. #ifdef VERBOSE
  614.             printf("WM_%cSCROLL, cntrl %x, cmd %x (%s)\n",
  615.                    message == WM_HSCROLL ?  'H' : 'V', param1, command,
  616.                    command == SB_LINELEFT ? "SB_LINELEFT/UP" :
  617.                    (command == SB_LINERIGHT ? "SB_LINERIGHT/DOWN" :
  618.                     (command == SB_PAGELEFT ? "SB_PAGELEFT/UP" :
  619.                      (command == SB_PAGERIGHT ? "SB_PAGERIGHT/DOWN" :
  620.                       (command == SB_SLIDERPOSITION ? "SB_SLIDERPOSITION" :
  621.                        (command == SB_SLIDERTRACK ? "SB_SLIDERTRACK" :
  622.                         (command == SB_ENDSCROLL ? "SB_ENDSCROLL" : "???"
  623.                     )))))));
  624. #endif
  625.  
  626.         WinQueryPointerPos(HWND_DESKTOP, &point);
  627.         Tk_TranslateOS2Event(NULLHANDLE, WM_MOUSEMOVE,
  628.             MPFROM2SHORT(point.x, point.y),
  629.                     MPFROM2SHORT(HT_NORMAL, KC_NONE), &result);
  630.  
  631.         if (command == SB_ENDSCROLL) {
  632.             /*
  633.              * Operator has finished scrolling but has not been doing any
  634.              * absolute positioning.
  635.              */
  636.         return 0;
  637.         }
  638.  
  639.         /*
  640.          * Bail out immediately if there isn't a command to invoke.
  641.          */
  642.  
  643.         if (scrollPtr->info.commandSize == 0) {
  644.         Tcl_ServiceAll();
  645.         return 0;
  646.         }
  647.         
  648.         Tcl_DStringInit(&cmdString);
  649.         Tcl_DStringAppend(&cmdString, scrollPtr->info.command,
  650.             scrollPtr->info.commandSize);
  651.         
  652.             /*
  653.              * The commands SB_LINELEFT and SB_LINEUP, SB_LINERIGHT and
  654.              * SB_LINEDOWN, SB_PAGELEFT and SB_PAGEUP and SB_PAGERIGHT and
  655.              * SB_PAGEDOWN are equivalent, but I'm trusting a good compiler
  656.              * will notice the superfluous values and eliminate them, rather
  657.              * than relying on this feature.
  658.              */
  659.         if (command == SB_LINELEFT || command == SB_LINEUP ||
  660.                 command == SB_LINERIGHT || command == SB_LINEDOWN) {
  661.         Tcl_DStringAppendElement(&cmdString, "scroll");
  662.         Tcl_DStringAppendElement(&cmdString,
  663.             (command == SB_LINELEFT || command == SB_LINEUP)
  664.                         ? "-1" : "1");
  665.         Tcl_DStringAppendElement(&cmdString, "units");
  666.         } else if (command == SB_PAGELEFT || command == SB_PAGEUP ||
  667.                        command == SB_PAGERIGHT || command == SB_PAGEDOWN) {
  668.         Tcl_DStringAppendElement(&cmdString, "scroll");
  669.         Tcl_DStringAppendElement(&cmdString,
  670.             (command == SB_PAGELEFT || command == SB_PAGEUP)
  671.                         ? "-1" : "1");
  672.         Tcl_DStringAppendElement(&cmdString, "pages");
  673.         } else {
  674.         char valueString[TCL_DOUBLE_SPACE];
  675.         double pos = 0.0;
  676.         switch (command) {
  677.             case SB_SLIDERPOSITION:
  678.             pos = ((double)SHORT1FROMMP(param2)) / MAX_SCROLL;
  679. #ifdef VERBOSE
  680.                         printf("SB_SLIDERPOSITION, pos %f\n", pos);
  681. #endif
  682.             break;
  683.  
  684.             case SB_SLIDERTRACK:
  685.             pos = ((double)SHORT1FROMMP(param2)) / MAX_SCROLL;
  686. #ifdef VERBOSE
  687.                         printf("SB_SLIDERTRACK, pos %f\n", pos);
  688. #endif
  689.             break;
  690.         }
  691.         sprintf(valueString, "%g", pos);
  692.         Tcl_DStringAppendElement(&cmdString, "moveto");
  693.         Tcl_DStringAppendElement(&cmdString, valueString);
  694.         }
  695.  
  696.         interp = scrollPtr->info.interp;
  697.         code = Tcl_GlobalEval(interp, cmdString.string);
  698.         if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) {
  699.         Tcl_AddErrorInfo(interp, "\n    (scrollbar command)");
  700.         Tcl_BackgroundError(interp);
  701.         }        
  702.         Tcl_DStringFree(&cmdString);        
  703.  
  704.         Tcl_ServiceAll();
  705.         return 0;
  706.     }
  707.  
  708.     default:
  709.         if (Tk_TranslateOS2Event(hwnd, message, param1, param2, &result)) {
  710.         return result;
  711.         }
  712.     }
  713.     return (*scrollPtr->oldProc)(hwnd, message, param1, param2);
  714. }
  715.  
  716. /*
  717.  *----------------------------------------------------------------------
  718.  *
  719.  * TkpConfigureScrollbar --
  720.  *
  721.  *    This procedure is called after the generic code has finished
  722.  *    processing configuration options, in order to configure
  723.  *    platform specific options.
  724.  *
  725.  * Results:
  726.  *    None.
  727.  *
  728.  * Side effects:
  729.  *    None.
  730.  *
  731.  *----------------------------------------------------------------------
  732.  */
  733.  
  734. void
  735. TkpConfigureScrollbar(scrollPtr)
  736.     register TkScrollbar *scrollPtr;    /* Information about widget;  may or
  737.                      * may not already have values for
  738.                      * some fields. */
  739. {
  740.  
  741. #ifdef VERBOSE
  742.     printf("TkpConfigureScrollbar\n");
  743. #endif
  744. }
  745.  
  746. /*
  747.  *--------------------------------------------------------------
  748.  *
  749.  * ScrollbarBindProc --
  750.  *
  751.  *    This procedure is invoked when the default <ButtonPress>
  752.  *    binding on the Scrollbar bind tag fires.
  753.  *
  754.  * Results:
  755.  *    None.
  756.  *
  757.  * Side effects:
  758.  *    The event enters a modal loop.
  759.  *
  760.  *--------------------------------------------------------------
  761.  */
  762.  
  763. static int
  764. ScrollbarBindProc(clientData, interp, eventPtr, tkwin, keySym)
  765.     ClientData clientData;
  766.     Tcl_Interp *interp;
  767.     XEvent *eventPtr;
  768.     Tk_Window tkwin;
  769.     KeySym keySym;
  770. {
  771.     TkWindow *winPtr = (TkWindow*)tkwin;
  772.  
  773. #ifdef VERBOSE
  774.     printf("ScrollbarBindProc (%s)\n", eventPtr->type == ButtonPress ?
  775.            "ButtonPress" : "not ButtonPress");
  776. #endif
  777.     if (eventPtr->type == ButtonPress) {
  778.     winPtr->flags |= TK_DEFER_MODAL;
  779.     }
  780.     return TCL_OK;
  781. }
  782.  
  783. /*
  784.  *----------------------------------------------------------------------
  785.  *
  786.  * ModalLoopProc --
  787.  *
  788.  *    This function is invoked at the end of the event processing
  789.  *    whenever the ScrollbarBindProc has been invoked for a ButtonPress
  790.  *    event. 
  791.  *
  792.  * Results:
  793.  *    None.
  794.  *
  795.  * Side effects:
  796.  *    Enters a modal loop.
  797.  *
  798.  *----------------------------------------------------------------------
  799.  */
  800.  
  801. static void
  802. ModalLoopProc(tkwin, eventPtr)
  803.     Tk_Window tkwin;
  804.     XEvent *eventPtr;
  805. {
  806.     TkWindow *winPtr = (TkWindow*)tkwin;
  807.     OS2Scrollbar *scrollPtr = (OS2Scrollbar *) winPtr->instanceData;
  808.     int oldMode;
  809.  
  810. #ifdef VERBOSE
  811.     printf("ModalLoopProc\n");
  812. #endif
  813.  
  814.     Tcl_Preserve((ClientData)scrollPtr);
  815.     scrollPtr->os2Flags |= IN_MODAL_LOOP;
  816.     oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  817.     TkOS2ResendEvent(scrollPtr->oldProc, scrollPtr->hwnd, eventPtr);
  818.     (void) Tcl_SetServiceMode(oldMode);
  819.     scrollPtr->os2Flags &= ~IN_MODAL_LOOP;
  820.     if (scrollPtr->hwnd && scrollPtr->os2Flags & ALREADY_DEAD) {
  821.     WinDestroyWindow(scrollPtr->hwnd);
  822.     }
  823.     Tcl_Release((ClientData)scrollPtr);
  824. }
  825.  
  826. /*
  827.  *--------------------------------------------------------------
  828.  *
  829.  * TkpScrollbarPosition --
  830.  *
  831.  *    Determine the scrollbar element corresponding to a
  832.  *    given position.
  833.  *
  834.  * Results:
  835.  *    One of TOP_ARROW, TOP_GAP, etc., indicating which element
  836.  *    of the scrollbar covers the position given by (x, y).  If
  837.  *    (x,y) is outside the scrollbar entirely, then OUTSIDE is
  838.  *    returned.
  839.  *
  840.  * Side effects:
  841.  *    None.
  842.  *
  843.  *--------------------------------------------------------------
  844.  */
  845.  
  846. int
  847. TkpScrollbarPosition(scrollPtr, x, y)
  848.     register TkScrollbar *scrollPtr;    /* Scrollbar widget record. */
  849.     int x, y;                /* Coordinates within scrollPtr's
  850.                      * window. */
  851. {
  852.     int length, width, tmp;
  853.  
  854.     if (scrollPtr->vertical) {
  855.     length = Tk_Height(scrollPtr->tkwin);
  856.     width = Tk_Width(scrollPtr->tkwin);
  857.     } else {
  858.     tmp = x;
  859.     x = y;
  860.     y = tmp;
  861.     length = Tk_Width(scrollPtr->tkwin);
  862.     width = Tk_Height(scrollPtr->tkwin);
  863.     }
  864.  
  865. #ifdef VERBOSE
  866.     printf("TkpScrollbarPosition USING x %d w %d y %d l %d i %d\n",
  867.                x, width, y, length, scrollPtr->inset);
  868. #endif
  869.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  870.         || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  871. #ifdef VERBOSE
  872.         printf("TkpScrollbarPosition OUTSIDE x %d w %d y %d l %d i %d\n",
  873.                x, width, y, length, scrollPtr->inset);
  874. #endif
  875.     return OUTSIDE;
  876.     }
  877.  
  878.     /*
  879.      * All of the calculations in this procedure mirror those in
  880.      * TkpDisplayScrollbar.  Be sure to keep the two consistent.
  881.      */
  882.  
  883.     if (y < (scrollPtr->inset + scrollPtr->arrowLength)) {
  884. #ifdef VERBOSE
  885.         printf("TkpScrollbarPosition TOP_ARROW\n");
  886. #endif
  887.     return TOP_ARROW;
  888.     }
  889.     if (y < scrollPtr->sliderFirst) {
  890. #ifdef VERBOSE
  891.         printf("TkpScrollbarPosition TOP_GAP\n");
  892. #endif
  893.     return TOP_GAP;
  894.     }
  895.     if (y < scrollPtr->sliderLast) {
  896. #ifdef VERBOSE
  897.         printf("TkpScrollbarPosition SLIDER\n");
  898. #endif
  899.     return SLIDER;
  900.     }
  901.     if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) {
  902. #ifdef VERBOSE
  903.         printf("TkpScrollbarPosition BOTTOM_ARROW\n");
  904. #endif
  905.     return BOTTOM_ARROW;
  906.     }
  907. #ifdef VERBOSE
  908.         printf("TkpScrollbarPosition BOTTOM_GAP\n");
  909. #endif
  910.     return BOTTOM_GAP;
  911. }
  912.