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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkMacScrollbar.c --
  3.  *
  4.  * This file implements the Macintosh specific portion of the scrollbar
  5.  * widget.  The Macintosh scrollbar may also draw a windows grow
  6.  * region under certain cases.
  7.  *
  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.  * RCS: @(#) $Id: tkMacScrlbr.c,v 1.6 2001/11/23 02:06:27 das Exp $
  14.  */
  15. #include "tkScrollbar.h"
  16. #include "tkMacInt.h"
  17. #include <Controls.h>
  18. #include <ControlDefinitions.h>
  19. /*
  20.  * The following definitions should really be in MacOS
  21.  * header files.  They are included here as this is the only
  22.  * file that needs the declarations.
  23.  */
  24. typedef pascal void (*ThumbActionFunc)(void);
  25. #if GENERATINGCFM
  26. typedef UniversalProcPtr ThumbActionUPP;
  27. #else
  28. typedef ThumbActionFunc ThumbActionUPP;
  29. #endif
  30. enum {
  31. uppThumbActionProcInfo = kPascalStackBased
  32. };
  33. #if GENERATINGCFM
  34. #define NewThumbActionProc(userRoutine)
  35. (ThumbActionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppThumbActionProcInfo, GetCurrentArchitecture())
  36. #else
  37. #define NewThumbActionProc(userRoutine)
  38. ((ThumbActionUPP) (userRoutine))
  39. #endif
  40. /*
  41.  * Minimum slider length, in pixels (designed to make sure that the slider
  42.  * is always easy to grab with the mouse).
  43.  */
  44. #define MIN_SLIDER_LENGTH 5
  45. /*
  46.  * Declaration of Windows specific scrollbar structure.
  47.  */
  48. typedef struct MacScrollbar {
  49.     TkScrollbar info; /* Generic scrollbar info. */
  50.     ControlRef sbHandle; /* Handle to the Scrollbar control struct. */
  51.     int macFlags; /* Various flags; see below. */
  52. } MacScrollbar;
  53. /*
  54.  * Flag bits for scrollbars on the Mac:
  55.  * 
  56.  * ALREADY_DEAD: Non-zero means this scrollbar has been
  57.  * destroyed, but has not been cleaned up.
  58.  * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle
  59.  * of a modal loop.
  60.  * ACTIVE: Non-zero means this window is currently
  61.  * active (in the foreground).
  62.  * FLUSH_TOP: Flush with top of Mac window.
  63.  * FLUSH_BOTTOM: Flush with bottom of Mac window.
  64.  * FLUSH_RIGHT: Flush with right of Mac window.
  65.  * FLUSH_LEFT: Flush with left of Mac window.
  66.  * SCROLLBAR_GROW: Non-zero means this window draws the grow
  67.  * region for the toplevel window.
  68.  * AUTO_ADJUST: Non-zero means we automatically adjust
  69.  * the size of the widget to align correctly
  70.  * along a Mac window.
  71.  * DRAW_GROW: Non-zero means we draw the grow region.
  72.  */
  73. #define ALREADY_DEAD 1
  74. #define IN_MODAL_LOOP 2
  75. #define ACTIVE 4
  76. #define FLUSH_TOP 8
  77. #define FLUSH_BOTTOM 16
  78. #define FLUSH_RIGHT 32
  79. #define FLUSH_LEFT 64
  80. #define SCROLLBAR_GROW 128
  81. #define AUTO_ADJUST 256
  82. #define DRAW_GROW 512
  83. /*
  84.  * Globals uses locally in this file.
  85.  */
  86. static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */
  87. static ThumbActionUPP thumbActionProc = NULL;    /* Pointer to func. */
  88. static TkScrollbar *activeScrollPtr = NULL;        /* Non-null when in thumb */
  89.  /* proc. */
  90. /*
  91.  * Forward declarations for procedures defined later in this file:
  92.  */
  93. static pascal void ScrollbarActionProc _ANSI_ARGS_((ControlRef theControl,
  94.     ControlPartCode partCode));
  95. static int ScrollbarBindProc _ANSI_ARGS_((ClientData clientData,
  96.     Tcl_Interp *interp, XEvent *eventPtr,
  97.     Tk_Window tkwin, KeySym keySym));
  98. static void ScrollbarEventProc _ANSI_ARGS_((
  99.     ClientData clientData, XEvent *eventPtr));
  100. static pascal void ThumbActionProc _ANSI_ARGS_((void));
  101. static void UpdateControlValues _ANSI_ARGS_((MacScrollbar *macScrollPtr));
  102.     
  103. /*
  104.  * The class procedure table for the scrollbar widget.  Leave the proc fields
  105.  * initialized to NULL, which should happen automatically because of the scope
  106.  * at which the variable is declared.
  107.  */
  108. Tk_ClassProcs tkpScrollbarProcs = {
  109.     sizeof(Tk_ClassProcs) /* size */
  110. };
  111. /*
  112.  *----------------------------------------------------------------------
  113.  *
  114.  * TkpCreateScrollbar --
  115.  *
  116.  * Allocate a new TkScrollbar structure.
  117.  *
  118.  * Results:
  119.  * Returns a newly allocated TkScrollbar structure.
  120.  *
  121.  * Side effects:
  122.  * None.
  123.  *
  124.  *----------------------------------------------------------------------
  125.  */
  126. TkScrollbar *
  127. TkpCreateScrollbar(
  128.     Tk_Window tkwin) /* New Tk Window. */
  129. {
  130.     MacScrollbar * macScrollPtr;
  131.     TkWindow *winPtr = (TkWindow *)tkwin;
  132.     
  133.     if (scrollActionProc == NULL) {
  134. scrollActionProc = NewControlActionProc(ScrollbarActionProc);
  135. thumbActionProc = NewThumbActionProc(ThumbActionProc);
  136.     }
  137.     macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar));
  138.     macScrollPtr->sbHandle = NULL;
  139.     macScrollPtr->macFlags = 0;
  140.     Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask|
  141.     StructureNotifyMask|FocusChangeMask,
  142.     ScrollbarEventProc, (ClientData) macScrollPtr);
  143.     if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
  144. Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL,
  145. (ClientData)1);
  146. TkCreateBindingProcedure(winPtr->mainPtr->interp,
  147. winPtr->mainPtr->bindingTable,
  148. (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
  149. ScrollbarBindProc, NULL, NULL);
  150.     }
  151.     return (TkScrollbar *) macScrollPtr;
  152. }
  153. /*
  154.  *--------------------------------------------------------------
  155.  *
  156.  * TkpDisplayScrollbar --
  157.  *
  158.  * This procedure redraws the contents of a scrollbar window.
  159.  * It is invoked as a do-when-idle handler, so it only runs
  160.  * when there's nothing else for the application to do.
  161.  *
  162.  * Results:
  163.  * None.
  164.  *
  165.  * Side effects:
  166.  * Information appears on the screen.
  167.  *
  168.  *--------------------------------------------------------------
  169.  */
  170. void
  171. TkpDisplayScrollbar(
  172.     ClientData clientData) /* Information about window. */
  173. {
  174.     register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  175.     register MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
  176.     register Tk_Window tkwin = scrollPtr->tkwin;
  177.     
  178.     MacDrawable *macDraw;
  179.     CGrafPtr saveWorld;
  180.     GDHandle saveDevice;
  181.     GWorldPtr destPort;
  182.     WindowRef windowRef;
  183.     
  184.     if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  185. goto done;
  186.     }
  187.     /*
  188.      * Draw the focus or any 3D relief we may have.
  189.      */
  190.     if (scrollPtr->highlightWidth != 0) {
  191. GC fgGC, bgGC;
  192. bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr,
  193. Tk_WindowId(tkwin));
  194. if (scrollPtr->flags & GOT_FOCUS) {
  195.     fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr,
  196.     Tk_WindowId(tkwin));
  197.     TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
  198. Tk_WindowId(tkwin));
  199. } else {
  200.     TkpDrawHighlightBorder(tkwin, bgGC, bgGC, scrollPtr->highlightWidth,
  201. Tk_WindowId(tkwin));
  202. }
  203.     }
  204.     Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
  205.     scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  206.     Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
  207.     Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
  208.     scrollPtr->borderWidth, scrollPtr->relief);
  209.     /*
  210.      * Set up port for drawing Macintosh control.
  211.      */
  212.     macDraw = (MacDrawable *) Tk_WindowId(tkwin);
  213.     destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin));
  214.     GetGWorld(&saveWorld, &saveDevice);
  215.     SetGWorld(destPort, NULL);
  216.     TkMacSetUpClippingRgn(Tk_WindowId(tkwin));
  217.     if (macScrollPtr->sbHandle == NULL) {
  218.         Rect r;
  219.         WindowRef frontNonFloating;
  220.         
  221.         r.left = r.top = 0;
  222.         r.right = r.bottom = 1;
  223. macScrollPtr->sbHandle = NewControl((WindowRef) destPort, &r, "p",
  224. false, (short) 500, 0, 1000,
  225. scrollBarProc, (SInt32) scrollPtr);
  226. /*
  227.  * If we are foremost than make us active.
  228.  */
  229. if (TkMacHaveAppearance() >= 0x110) {
  230.     frontNonFloating = FrontNonFloatingWindow();
  231. } else {
  232.     frontNonFloating = FrontWindow();
  233. }
  234. if ((WindowPtr) destPort == FrontWindow() || TkpIsWindowFloating((WindowPtr) destPort)) {
  235.     macScrollPtr->macFlags |= ACTIVE;
  236. }
  237.     }
  238.     /*
  239.      * Update the control values before we draw.
  240.      */
  241.     windowRef  = (**macScrollPtr->sbHandle).contrlOwner;    
  242.     UpdateControlValues(macScrollPtr);
  243.     
  244.     if (macScrollPtr->macFlags & ACTIVE) {
  245. Draw1Control(macScrollPtr->sbHandle);
  246. if (macScrollPtr->macFlags & DRAW_GROW) {
  247.     DrawGrowIcon(windowRef);
  248. }
  249.     } else {
  250. (**macScrollPtr->sbHandle).contrlHilite = 255;
  251. Draw1Control(macScrollPtr->sbHandle);
  252. if (macScrollPtr->macFlags & DRAW_GROW) {
  253.     DrawGrowIcon(windowRef);
  254.     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
  255. Tk_Width(tkwin) - 13, Tk_Height(tkwin) - 13,
  256. Tk_Width(tkwin), Tk_Height(tkwin),
  257. 0, TK_RELIEF_FLAT);
  258. }
  259.     }
  260.     
  261.     SetGWorld(saveWorld, saveDevice);
  262.      
  263.     done:
  264.     scrollPtr->flags &= ~REDRAW_PENDING;
  265. }
  266. /*
  267.  *----------------------------------------------------------------------
  268.  *
  269.  * TkpConfigureScrollbar --
  270.  *
  271.  * This procedure is called after the generic code has finished
  272.  * processing configuration options, in order to configure
  273.  * platform specific options.
  274.  *
  275.  * Results:
  276.  * None.
  277.  *
  278.  * Side effects:
  279.  * None.
  280.  *
  281.  *----------------------------------------------------------------------
  282.  */
  283. void
  284. TkpConfigureScrollbar(scrollPtr)
  285.     register TkScrollbar *scrollPtr; /* Information about widget;  may or
  286.  * may not already have values for
  287.  * some fields. */
  288. {
  289. }
  290. /*
  291.  *----------------------------------------------------------------------
  292.  *
  293.  * TkpComputeScrollbarGeometry --
  294.  *
  295.  * After changes in a scrollbar's size or configuration, this
  296.  * procedure recomputes various geometry information used in
  297.  * displaying the scrollbar.
  298.  *
  299.  * Results:
  300.  * None.
  301.  *
  302.  * Side effects:
  303.  * The scrollbar will be displayed differently.
  304.  *
  305.  *----------------------------------------------------------------------
  306.  */
  307. void
  308. TkpComputeScrollbarGeometry(
  309.     register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may
  310.  * have changed. */
  311. {
  312.     MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
  313.     int width, fieldLength, adjust = 0;
  314.     if (scrollPtr->highlightWidth < 0) {
  315. scrollPtr->highlightWidth = 0;
  316.     }
  317.     scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
  318.     width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
  319.     : Tk_Height(scrollPtr->tkwin);
  320.     scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1;
  321.     fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
  322.     : Tk_Width(scrollPtr->tkwin))
  323.     - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  324.     if (fieldLength < 0) {
  325. fieldLength = 0;
  326.     }
  327.     scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
  328.     scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
  329.     /*
  330.      * Adjust the slider so that some piece of it is always
  331.      * displayed in the scrollbar and so that it has at least
  332.      * a minimal width (so it can be grabbed with the mouse).
  333.      */
  334.     if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
  335. scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
  336.     }
  337.     if (scrollPtr->sliderFirst < 0) {
  338. scrollPtr->sliderFirst = 0;
  339.     }
  340.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  341.     + MIN_SLIDER_LENGTH)) {
  342. scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
  343.     }
  344.     if (scrollPtr->sliderLast > fieldLength) {
  345. scrollPtr->sliderLast = fieldLength;
  346.     }
  347.     scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
  348.     scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
  349.     /*
  350.      * Register the desired geometry for the window (leave enough space
  351.      * for the two arrows plus a minimum-size slider, plus border around
  352.      * the whole window, if any).  Then arrange for the window to be
  353.      * redisplayed.
  354.      */
  355.     if (scrollPtr->vertical) {
  356. if ((macScrollPtr->macFlags & AUTO_ADJUST) &&
  357. (macScrollPtr->macFlags & (FLUSH_RIGHT|FLUSH_LEFT))) {
  358.     adjust--;
  359. }
  360. Tk_GeometryRequest(scrollPtr->tkwin,
  361. scrollPtr->width + 2*scrollPtr->inset + adjust,
  362. 2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  363. + scrollPtr->inset));
  364.     } else {
  365. if ((macScrollPtr->macFlags & AUTO_ADJUST) &&
  366. (macScrollPtr->macFlags & (FLUSH_TOP|FLUSH_BOTTOM))) {
  367.     adjust--;
  368. }
  369. Tk_GeometryRequest(scrollPtr->tkwin,
  370. 2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  371. + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset + adjust);
  372.     }
  373.     Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
  374. }
  375. /*
  376.  *----------------------------------------------------------------------
  377.  *
  378.  * TkpDestroyScrollbar --
  379.  *
  380.  * Free data structures associated with the scrollbar control.
  381.  *
  382.  * Results:
  383.  * None.
  384.  *
  385.  * Side effects:
  386.  * None.
  387.  *
  388.  *----------------------------------------------------------------------
  389.  */
  390. void
  391. TkpDestroyScrollbar(
  392.     TkScrollbar *scrollPtr) /* Scrollbar to destroy. */
  393. {
  394.     MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
  395.     if (macScrollPtr->sbHandle != NULL) {
  396. if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) {
  397.     DisposeControl(macScrollPtr->sbHandle);
  398.     macScrollPtr->sbHandle = NULL;
  399. }
  400.     }
  401.     macScrollPtr->macFlags |= ALREADY_DEAD;
  402. }
  403. /*
  404.  *--------------------------------------------------------------
  405.  *
  406.  * TkpScrollbarPosition --
  407.  *
  408.  * Determine the scrollbar element corresponding to a
  409.  * given position.
  410.  *
  411.  * Results:
  412.  * One of TOP_ARROW, TOP_GAP, etc., indicating which element
  413.  * of the scrollbar covers the position given by (x, y).  If
  414.  * (x,y) is outside the scrollbar entirely, then OUTSIDE is
  415.  * returned.
  416.  *
  417.  * Side effects:
  418.  * None.
  419.  *
  420.  *--------------------------------------------------------------
  421.  */
  422. int
  423. TkpScrollbarPosition(
  424.     TkScrollbar *scrollPtr, /* Scrollbar widget record. */
  425.     int x, int y) /* Coordinates within scrollPtr's
  426.  * window. */
  427. {
  428.     MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
  429.     GWorldPtr destPort;
  430.     int length, width, tmp, inactive = false;
  431.     ControlPartCode part;
  432.     Point where;
  433.     Rect bounds;
  434.     if (scrollPtr->vertical) {
  435. length = Tk_Height(scrollPtr->tkwin);
  436. width = Tk_Width(scrollPtr->tkwin);
  437.     } else {
  438. tmp = x;
  439. x = y;
  440. y = tmp;
  441. length = Tk_Width(scrollPtr->tkwin);
  442. width = Tk_Height(scrollPtr->tkwin);
  443.     }
  444.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  445.     || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  446. return OUTSIDE;
  447.     }
  448.     /*
  449.      * All of the calculations in this procedure mirror those in
  450.      * DisplayScrollbar.  Be sure to keep the two consistent.  On the 
  451.      * Macintosh we use the OS call TestControl to do this mapping.
  452.      * For TestControl to work, the scrollbar must be active and must
  453.      * be in the current port.
  454.      */
  455.     destPort = TkMacGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
  456.     SetGWorld(destPort, NULL);
  457.     UpdateControlValues(macScrollPtr);
  458.     if ((**macScrollPtr->sbHandle).contrlHilite == 255) {
  459. inactive = true;
  460. (**macScrollPtr->sbHandle).contrlHilite = 0;
  461.     }
  462.     TkMacWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);
  463.     where.h = x + bounds.left;
  464.     where.v = y + bounds.top;
  465.     part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where);
  466.     if (inactive) {
  467. (**macScrollPtr->sbHandle).contrlHilite = 255;
  468.     }
  469.     switch (part) {
  470.      case kControlUpButtonPart:
  471.     return TOP_ARROW;
  472.      case kControlPageUpPart:
  473.     return TOP_GAP;
  474.      case kControlIndicatorPart:
  475.     return SLIDER;
  476.      case kControlPageDownPart:
  477.     return BOTTOM_GAP;
  478.      case kControlDownButtonPart:
  479.     return BOTTOM_ARROW;
  480.      default:
  481.     return OUTSIDE;
  482.     }
  483. }
  484. /*
  485.  *--------------------------------------------------------------
  486.  *
  487.  * ThumbActionProc --
  488.  *
  489.  * Callback procedure used by the Macintosh toolbox call
  490.  * TrackControl.  This call is used to track the thumb of
  491.  * the scrollbar.  Unlike the ScrollbarActionProc function
  492.  * this function is called once and basically takes over
  493.  * tracking the scrollbar from the control.  This is done
  494.  * to avoid conflicts with what the control plans to draw.
  495.  *
  496.  * Results:
  497.  * None.
  498.  *
  499.  * Side effects:
  500.  * May change the display.
  501.  *
  502.  *--------------------------------------------------------------
  503.  */
  504. static pascal void
  505. ThumbActionProc()
  506. {
  507.     register TkScrollbar *scrollPtr = activeScrollPtr;
  508.     register MacScrollbar *macScrollPtr = (MacScrollbar *) activeScrollPtr;
  509.     Tcl_DString cmdString;
  510.     Rect nullRect = {0,0,0,0};
  511.     int origValue, trackBarPin;
  512.     double thumbWidth, newFirstFraction, trackBarSize;
  513.     char vauleString[40];
  514.     Point currentPoint = { 0, 0 };
  515.     Point lastPoint = { 0, 0 };
  516.     Rect trackRect;
  517.     Tcl_Interp *interp;
  518.     
  519.     if (scrollPtr == NULL) {
  520. return;
  521.     }
  522.     Tcl_DStringInit(&cmdString);
  523.     
  524.     /*
  525.      * First compute values that will remain constant during the tracking
  526.      * of the thumb.  The variable trackBarSize is the length of the scrollbar
  527.      * minus the 2 arrows and half the width of the thumb on both sides
  528.      * (3 * arrowLength).  The variable trackBarPin is the lower starting point
  529.      * of the drag region.
  530.      *
  531.      * Note: the arrowLength is equal to the thumb width of a Mac scrollbar.
  532.      */
  533.     origValue = GetControlValue(macScrollPtr->sbHandle);
  534.     trackRect = (**macScrollPtr->sbHandle).contrlRect;
  535.     if (scrollPtr->vertical == true) {
  536. trackBarSize = (double) (trackRect.bottom - trackRect.top
  537. - (scrollPtr->arrowLength * 3));
  538. trackBarPin = trackRect.top + scrollPtr->arrowLength
  539.     + (scrollPtr->arrowLength / 2);
  540. InsetRect(&trackRect, -25, -113);
  541.     } else {
  542. trackBarSize = (double) (trackRect.right - trackRect.left
  543. - (scrollPtr->arrowLength * 3));
  544. trackBarPin = trackRect.left + scrollPtr->arrowLength
  545.     + (scrollPtr->arrowLength / 2);
  546. InsetRect(&trackRect, -113, -25);
  547.     }
  548.     /*
  549.      * Track the mouse while the button is held down.  If the mouse is moved,
  550.      * we calculate the value that should be passed to the "command" part of
  551.      * the scrollbar.
  552.      */
  553.     while (StillDown()) {
  554. GetMouse(&currentPoint);
  555. if (EqualPt(currentPoint, lastPoint)) {
  556.     continue;
  557. }
  558. lastPoint = currentPoint;
  559. /*
  560.  * Calculating this value is a little tricky.  We need to calculate a
  561.  * value for where the thumb would be in a Motif widget (variable
  562.  * thumb).  This value is what the "command" expects and is what will
  563.  * be resent to the scrollbar to update its value.
  564.  */
  565. thumbWidth = scrollPtr->lastFraction - scrollPtr->firstFraction;
  566. if (PtInRect(currentPoint, &trackRect)) {
  567.     if (scrollPtr->vertical == true) {
  568. newFirstFraction =  (1.0 - thumbWidth) *
  569.     ((double) (currentPoint.v - trackBarPin) / trackBarSize);
  570.     } else {
  571. newFirstFraction =  (1.0 - thumbWidth) *
  572.     ((double) (currentPoint.h - trackBarPin) / trackBarSize);
  573.     }
  574. } else {
  575.     newFirstFraction = ((double) origValue / 1000.0)
  576. * (1.0 - thumbWidth);
  577. }
  578. sprintf(vauleString, "%g", newFirstFraction);
  579. Tcl_DStringSetLength(&cmdString, 0);
  580. Tcl_DStringAppend(&cmdString, scrollPtr->command,
  581. scrollPtr->commandSize);
  582. Tcl_DStringAppendElement(&cmdString, "moveto");
  583. Tcl_DStringAppendElement(&cmdString, vauleString);
  584.         interp = scrollPtr->interp;
  585.         Tcl_Preserve((ClientData) interp);
  586. Tcl_GlobalEval(interp, cmdString.string);
  587.         Tcl_Release((ClientData) interp);
  588. Tcl_DStringSetLength(&cmdString, 0);
  589. Tcl_DStringAppend(&cmdString, "update idletasks",
  590. strlen("update idletasks"));
  591.         Tcl_Preserve((ClientData) interp);
  592. Tcl_GlobalEval(interp, cmdString.string);
  593.         Tcl_Release((ClientData) interp);
  594.     }
  595.     
  596.     /*
  597.      * This next bit of code is a bit of a hack - but needed.  The problem is
  598.      * that the control wants to draw the drag outline if the control value
  599.      * changes during the drag (which it does).  What we do here is change the
  600.      * clip region to hide this drawing from the user.
  601.      */
  602.     ClipRect(&nullRect);
  603.     
  604.     Tcl_DStringFree(&cmdString);
  605.     return;
  606. }
  607. /*
  608.  *--------------------------------------------------------------
  609.  *
  610.  * ScrollbarActionProc --
  611.  *
  612.  * Callback procedure used by the Macintosh toolbox call
  613.  * TrackControl.  This call will update the display while
  614.  * the scrollbar is being manipulated by the user.
  615.  *
  616.  * Results:
  617.  * None.
  618.  *
  619.  * Side effects:
  620.  * May change the display.
  621.  *
  622.  *--------------------------------------------------------------
  623.  */
  624. static pascal void
  625. ScrollbarActionProc(
  626.     ControlRef theControl,  /* Handle to scrollbat control */
  627.     ControlPartCode partCode) /* Part of scrollbar that was "hit" */
  628. {
  629.     register TkScrollbar *scrollPtr = (TkScrollbar *) GetControlReference(theControl);
  630.     Tcl_DString cmdString;
  631.     
  632.     Tcl_DStringInit(&cmdString);
  633.     Tcl_DStringAppend(&cmdString, scrollPtr->command,
  634.     scrollPtr->commandSize);
  635.     if (partCode == kControlUpButtonPart || partCode == kControlDownButtonPart) {
  636. Tcl_DStringAppendElement(&cmdString, "scroll");
  637. Tcl_DStringAppendElement(&cmdString,
  638. (partCode == kControlUpButtonPart ) ? "-1" : "1");
  639. Tcl_DStringAppendElement(&cmdString, "unit");
  640.     } else if (partCode == kControlPageUpPart || partCode == kControlPageDownPart) {
  641. Tcl_DStringAppendElement(&cmdString, "scroll");
  642. Tcl_DStringAppendElement(&cmdString,
  643. (partCode == kControlPageUpPart ) ? "-1" : "1");
  644. Tcl_DStringAppendElement(&cmdString, "page");
  645.     }
  646.     Tcl_Preserve((ClientData) scrollPtr->interp);
  647.     Tcl_DStringAppend(&cmdString, "; update idletasks",
  648. strlen("; update idletasks"));
  649.     Tcl_GlobalEval(scrollPtr->interp, cmdString.string);
  650.     Tcl_Release((ClientData) scrollPtr->interp);
  651.     Tcl_DStringFree(&cmdString);
  652. }
  653. /*
  654.  *--------------------------------------------------------------
  655.  *
  656.  * ScrollbarBindProc --
  657.  *
  658.  * This procedure is invoked when the default <ButtonPress>
  659.  * binding on the Scrollbar bind tag fires.
  660.  *
  661.  * Results:
  662.  * None.
  663.  *
  664.  * Side effects:
  665.  * The event enters a modal loop.
  666.  *
  667.  *--------------------------------------------------------------
  668.  */
  669. static int
  670. ScrollbarBindProc(
  671.     ClientData clientData, /* Not used. */
  672.     Tcl_Interp *interp, /* Interp with binding. */
  673.     XEvent *eventPtr, /* X event that triggered binding. */
  674.     Tk_Window tkwin, /* Target window for event. */
  675.     KeySym keySym) /* The KeySym if a key event. */
  676. {
  677.     TkWindow *winPtr = (TkWindow*)tkwin;
  678.     TkScrollbar *scrollPtr = (TkScrollbar *) winPtr->instanceData;
  679.     MacScrollbar *macScrollPtr = (MacScrollbar *) winPtr->instanceData;
  680.     Tcl_Preserve((ClientData)scrollPtr);
  681.     macScrollPtr->macFlags |= IN_MODAL_LOOP;
  682.     
  683.     if (eventPtr->type == ButtonPress) {
  684.      Point where;
  685.      Rect bounds;
  686.      int part, x, y, dummy;
  687.      unsigned int state;
  688. CGrafPtr saveWorld;
  689. GDHandle saveDevice;
  690. GWorldPtr destPort;
  691. Window window;
  692. /*
  693.  * To call Macintosh control routines we must have the port
  694.  * set to the window containing the control.  We will then test
  695.  * which part of the control was hit and act accordingly.
  696.  */
  697. destPort = TkMacGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
  698. GetGWorld(&saveWorld, &saveDevice);
  699. SetGWorld(destPort, NULL);
  700. TkMacSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin));
  701. TkMacWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);
  702.      where.h = eventPtr->xbutton.x + bounds.left;
  703.      where.v = eventPtr->xbutton.y + bounds.top;
  704. part = TestControl(macScrollPtr->sbHandle, where);
  705. if (part == kControlIndicatorPart && scrollPtr->jump == false) {
  706.     /*
  707.      * Case 1: In thumb, no jump scrolling.  Call track control
  708.      * with the thumb action proc which will do most of the work.
  709.      * Set the global activeScrollPtr to the current control
  710.      * so the callback may have access to it.
  711.      */
  712.     activeScrollPtr = scrollPtr;
  713.     part = TrackControl(macScrollPtr->sbHandle, where,
  714.     (ControlActionUPP) thumbActionProc);
  715.     activeScrollPtr = NULL;
  716. } else if (part == kControlIndicatorPart) {
  717.     /*
  718.      * Case 2: in thumb with jump scrolling.  Call TrackControl
  719.      * with a NULL action proc.  Use the new value of the control
  720.      * to set update the control.
  721.      */
  722.     part = TrackControl(macScrollPtr->sbHandle, where, NULL);
  723.     if (part == kControlIndicatorPart) {
  724.      double newFirstFraction, thumbWidth;
  725. Tcl_DString cmdString;
  726. char vauleString[TCL_DOUBLE_SPACE];
  727. /*
  728.  * The following calculation takes the new control
  729.  * value and maps it to what Tk needs for its variable
  730.  * thumb size representation.
  731.  */
  732. thumbWidth = scrollPtr->lastFraction
  733.      - scrollPtr->firstFraction;
  734. newFirstFraction = (1.0 - thumbWidth) *
  735.     ((double) GetControlValue(macScrollPtr->sbHandle) / 1000.0);
  736. sprintf(vauleString, "%g", newFirstFraction);
  737. Tcl_DStringInit(&cmdString);
  738. Tcl_DStringAppend(&cmdString, scrollPtr->command,
  739. strlen(scrollPtr->command));
  740. Tcl_DStringAppendElement(&cmdString, "moveto");
  741. Tcl_DStringAppendElement(&cmdString, vauleString);
  742. Tcl_DStringAppend(&cmdString, "; update idletasks",
  743. strlen("; update idletasks"));
  744.                 interp = scrollPtr->interp;
  745.                 Tcl_Preserve((ClientData) interp);
  746. Tcl_GlobalEval(interp, cmdString.string);
  747.                 Tcl_Release((ClientData) interp);
  748. Tcl_DStringFree(&cmdString);
  749.     }
  750. } else if (part != 0) {
  751.     /*
  752.      * Case 3: in any other part of the scrollbar.  We call
  753.      * TrackControl with the scrollActionProc which will do
  754.      * most all the work.
  755.      */
  756.     TrackControl(macScrollPtr->sbHandle, where, scrollActionProc);
  757.     HiliteControl(macScrollPtr->sbHandle, 0);
  758. }
  759. /*
  760.  * The TrackControl call will "eat" the ButtonUp event.  We now
  761.  * generate a ButtonUp event so Tk will unset implicit grabs etc.
  762.  */
  763. GetMouse(&where);
  764. XQueryPointer(NULL, None, &window, &window, &x,
  765.     &y, &dummy, &dummy, &state);
  766. window = Tk_WindowId(scrollPtr->tkwin);
  767. TkGenerateButtonEvent(x, y, window, state);
  768. SetGWorld(saveWorld, saveDevice);
  769.     }
  770.     if (macScrollPtr->sbHandle && (macScrollPtr->macFlags & ALREADY_DEAD)) {
  771. DisposeControl(macScrollPtr->sbHandle);
  772. macScrollPtr->sbHandle = NULL;
  773.     }
  774.     macScrollPtr->macFlags &= ~IN_MODAL_LOOP;
  775.     Tcl_Release((ClientData)scrollPtr);
  776.     
  777.     return TCL_OK;
  778. }
  779. /*
  780.  *--------------------------------------------------------------
  781.  *
  782.  * ScrollbarEventProc --
  783.  *
  784.  * This procedure is invoked by the Tk dispatcher for various
  785.  * events on scrollbars.
  786.  *
  787.  * Results:
  788.  * None.
  789.  *
  790.  * Side effects:
  791.  * When the window gets deleted, internal structures get
  792.  * cleaned up.  When it gets exposed, it is redisplayed.
  793.  *
  794.  *--------------------------------------------------------------
  795.  */
  796. static void
  797. ScrollbarEventProc(
  798.     ClientData clientData, /* Information about window. */
  799.     XEvent *eventPtr) /* Information about event. */
  800. {
  801.     TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  802.     MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
  803.     if (eventPtr->type == UnmapNotify) {
  804. TkMacSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false);
  805.     } else if (eventPtr->type == ActivateNotify) {
  806. macScrollPtr->macFlags |= ACTIVE;
  807. TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
  808.     } else if (eventPtr->type == DeactivateNotify) {
  809. macScrollPtr->macFlags &= ~ACTIVE;
  810. TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
  811.     } else {
  812. TkScrollbarEventProc(clientData, eventPtr);
  813.     }
  814. }
  815. /*
  816.  *--------------------------------------------------------------
  817.  *
  818.  * UpdateControlValues --
  819.  *
  820.  * This procedure updates the Macintosh scrollbar control
  821.  * to display the values defined by the Tk scrollbar.
  822.  *
  823.  * Results:
  824.  * None.
  825.  *
  826.  * Side effects:
  827.  * The Macintosh control is updated.
  828.  *
  829.  *--------------------------------------------------------------
  830.  */
  831. static void
  832. UpdateControlValues(
  833.     MacScrollbar *macScrollPtr) /* Scrollbar data struct. */
  834. {
  835.     TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr;
  836.     Tk_Window tkwin = scrollPtr->tkwin;
  837.     MacDrawable * macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
  838.     WindowRef windowRef  = (**macScrollPtr->sbHandle).contrlOwner;    
  839.     double middle;
  840.     int drawGrowRgn = false;
  841.     int flushRight = false;
  842.     int flushBottom = false;
  843.     /*
  844.      * We can't use the Macintosh commands SizeControl and MoveControl as these
  845.      * calls will also cause a redraw which in our case will also cause
  846.      * flicker.  To avoid this we adjust the control record directly.  The
  847.      * Draw1Control command appears to just draw where ever the control says to
  848.      * draw so this seems right.
  849.      *
  850.      * NOTE: changing the control record directly may not work when
  851.      * Apple releases the Copland version of the MacOS (or when hell is cold).
  852.      */
  853.      
  854.     (**macScrollPtr->sbHandle).contrlRect.left = macDraw->xOff + scrollPtr->inset;
  855.     (**macScrollPtr->sbHandle).contrlRect.top = macDraw->yOff + scrollPtr->inset;
  856.     (**macScrollPtr->sbHandle).contrlRect.right = macDraw->xOff + Tk_Width(tkwin)
  857. - scrollPtr->inset;
  858.     (**macScrollPtr->sbHandle).contrlRect.bottom = macDraw->yOff +
  859. Tk_Height(tkwin) - scrollPtr->inset;
  860.     
  861.     /*
  862.      * To make Tk applications look more like Macintosh applications without 
  863.      * requiring additional work by the Tk developer we do some cute tricks.
  864.      * The first trick plays with the size of the widget to get it to overlap
  865.      * with the side of the window by one pixel (we don't do this if the placer
  866.      * is the geometry manager).  The second trick shrinks the scrollbar if it
  867.      * it covers the area of the grow region ao the scrollbar can also draw
  868.      * the grow region if need be.
  869.      */
  870.     if (!strcmp(macDraw->winPtr->geomMgrPtr->name, "place")) {
  871. macScrollPtr->macFlags &= AUTO_ADJUST;
  872.     } else {
  873. macScrollPtr->macFlags |= AUTO_ADJUST;
  874.     }
  875.     /* TODO: use accessor function!!! */
  876.     if (windowRef->portRect.left == (**macScrollPtr->sbHandle).contrlRect.left) {
  877. if (macScrollPtr->macFlags & AUTO_ADJUST) {
  878.     (**macScrollPtr->sbHandle).contrlRect.left--;
  879. }
  880. if (!(macScrollPtr->macFlags & FLUSH_LEFT)) {
  881.     macScrollPtr->macFlags |= FLUSH_LEFT;
  882.     if (scrollPtr->vertical) {
  883. TkpComputeScrollbarGeometry(scrollPtr);
  884.     }
  885. }
  886.     } else if (macScrollPtr->macFlags & FLUSH_LEFT) {
  887. macScrollPtr->macFlags &= ~FLUSH_LEFT;
  888. if (scrollPtr->vertical) {
  889.     TkpComputeScrollbarGeometry(scrollPtr);
  890. }
  891.     }
  892.     
  893.     if (windowRef->portRect.top == (**macScrollPtr->sbHandle).contrlRect.top) {
  894. if (macScrollPtr->macFlags & AUTO_ADJUST) {
  895.     (**macScrollPtr->sbHandle).contrlRect.top--;
  896. }
  897. if (!(macScrollPtr->macFlags & FLUSH_TOP)) {
  898.     macScrollPtr->macFlags |= FLUSH_TOP;
  899.     if (! scrollPtr->vertical) {
  900. TkpComputeScrollbarGeometry(scrollPtr);
  901.     }
  902. }
  903.     } else if (macScrollPtr->macFlags & FLUSH_TOP) {
  904. macScrollPtr->macFlags &= ~FLUSH_TOP;
  905. if (! scrollPtr->vertical) {
  906.     TkpComputeScrollbarGeometry(scrollPtr);
  907. }
  908.     }
  909.     if (windowRef->portRect.right == (**macScrollPtr->sbHandle).contrlRect.right) {
  910. flushRight = true;
  911. if (macScrollPtr->macFlags & AUTO_ADJUST) {
  912.     (**macScrollPtr->sbHandle).contrlRect.right++;
  913. }
  914. if (!(macScrollPtr->macFlags & FLUSH_RIGHT)) {
  915.     macScrollPtr->macFlags |= FLUSH_RIGHT;
  916.     if (scrollPtr->vertical) {
  917. TkpComputeScrollbarGeometry(scrollPtr);
  918.     }
  919. }
  920.     } else if (macScrollPtr->macFlags & FLUSH_RIGHT) {
  921. macScrollPtr->macFlags &= ~FLUSH_RIGHT;
  922. if (scrollPtr->vertical) {
  923.     TkpComputeScrollbarGeometry(scrollPtr);
  924. }
  925.     }
  926.     if (windowRef->portRect.bottom == (**macScrollPtr->sbHandle).contrlRect.bottom) {
  927. flushBottom = true;
  928. if (macScrollPtr->macFlags & AUTO_ADJUST) {
  929.     (**macScrollPtr->sbHandle).contrlRect.bottom++;
  930. }
  931. if (!(macScrollPtr->macFlags & FLUSH_BOTTOM)) {
  932.     macScrollPtr->macFlags |= FLUSH_BOTTOM;
  933.     if (! scrollPtr->vertical) {
  934. TkpComputeScrollbarGeometry(scrollPtr);
  935.     }
  936. }
  937.     } else if (macScrollPtr->macFlags & FLUSH_BOTTOM) {
  938. macScrollPtr->macFlags &= ~FLUSH_BOTTOM;
  939. if (! scrollPtr->vertical) {
  940.     TkpComputeScrollbarGeometry(scrollPtr);
  941. }
  942.     }
  943.     /*
  944.      * If the scrollbar is flush against the bottom right hand coner then
  945.      * it may need to draw the grow region for the window so we let the
  946.      * wm code know about this scrollbar.  We don't actually draw the grow
  947.      * region, however, unless we are currently resizable.
  948.      */
  949.     macScrollPtr->macFlags &= ~DRAW_GROW;
  950.     if (flushBottom && flushRight) {
  951. TkMacSetScrollbarGrow((TkWindow *) tkwin, true);
  952. if (TkMacResizable(macDraw->toplevel->winPtr)) {
  953.     if (scrollPtr->vertical) {
  954. (**macScrollPtr->sbHandle).contrlRect.bottom -= 14;
  955.     } else {
  956. (**macScrollPtr->sbHandle).contrlRect.right -= 14;
  957.     }
  958.     macScrollPtr->macFlags |= DRAW_GROW;
  959. }
  960.     } else {
  961. TkMacSetScrollbarGrow((TkWindow *) tkwin, false);
  962.     }
  963.     
  964.     /*
  965.      * Given the Tk parameters for the fractions of the start and
  966.      * end of the thumb, the following calculation determines the
  967.      * location for the fixed sized Macintosh thumb.
  968.      */
  969.     middle = scrollPtr->firstFraction / (scrollPtr->firstFraction +
  970.     (1.0 - scrollPtr->lastFraction));
  971.     (**macScrollPtr->sbHandle).contrlValue = (short) (middle * 1000);
  972.     if ((**macScrollPtr->sbHandle).contrlHilite == 0 || 
  973. (**macScrollPtr->sbHandle).contrlHilite == 255) {
  974. if (scrollPtr->firstFraction == 0.0 &&
  975. scrollPtr->lastFraction == 1.0) {
  976.     (**macScrollPtr->sbHandle).contrlHilite = 255;
  977. } else {
  978.     (**macScrollPtr->sbHandle).contrlHilite = 0;
  979. }
  980.     }
  981.     if ((**macScrollPtr->sbHandle).contrlVis != 255) {
  982. (**macScrollPtr->sbHandle).contrlVis = 255;
  983.     }
  984. }