2 * tkMacOSXScrollbar.c --
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.
8 * Copyright (c) 1996 by Sun Microsystems, Inc.
9 * Copyright 2001, Apple Computer, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 #include "tkScrollbar.h"
18 #include "tkMacOSXInt.h"
20 #include <Carbon/Carbon.h>
22 #include "tkMacOSXDebug.h"
24 * The following definitions should really be in MacOS
25 * header files. They are included here as this is the only
26 * file that needs the declarations.
28 typedef pascal void (*ThumbActionFunc)(void);
30 typedef ThumbActionFunc ThumbActionUPP;
33 uppThumbActionProcInfo = kPascalStackBased
36 #define NewThumbActionProc(userRoutine) ((ThumbActionUPP) (userRoutine))
39 * Minimum slider length, in pixels (designed to make sure that the slider
40 * is always easy to grab with the mouse).
43 #define MIN_SLIDER_LENGTH 5
44 #define MIN_SCROLLBAR_VALUE 0
45 #define MAX_SCROLLBAR_VALUE 1000
46 #define MAX_SCROLLBAR_DVALUE 1000.0
49 * Declaration of Windows specific scrollbar structure.
52 typedef struct MacScrollbar {
53 TkScrollbar info; /* Generic scrollbar info */
54 ControlRef sbHandle; /* Opaque handle to the Scrollbar contol struct */
55 int macFlags; /* Various flags; see below */
58 /* Handle to the Scrollbar control structure */
62 * Flag bits for scrollbars on the Mac:
64 * ALREADY_DEAD: Non-zero means this scrollbar has been
65 * destroyed, but has not been cleaned up.
66 * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle
68 * ACTIVE: Non-zero means this window is currently
69 * active (in the foreground).
70 * FLUSH_TOP: Flush with top of Mac window.
71 * FLUSH_BOTTOM: Flush with bottom of Mac window.
72 * FLUSH_RIGHT: Flush with right of Mac window.
73 * FLUSH_LEFT: Flush with left of Mac window.
74 * SCROLLBAR_GROW: Non-zero means this window draws the grow
75 * region for the toplevel window.
76 * AUTO_ADJUST: Non-zero means we automatically adjust
77 * the size of the widget to align correctly
79 * DRAW_GROW: Non-zero means we draw the grow region.
82 #define ALREADY_DEAD 1
83 #define IN_MODAL_LOOP 2
86 #define FLUSH_BOTTOM 16
87 #define FLUSH_RIGHT 32
89 #define SCROLLBAR_GROW 128
90 #define AUTO_ADJUST 256
94 * Globals uses locally in this file.
96 static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */
97 static ThumbActionUPP thumbActionProc = NULL; /* Pointer to func. */
98 static TkScrollbar *activeScrollPtr = NULL; /* Non-null when in thumb */
101 * Forward declarations for procedures defined later in this file:
104 static pascal void ScrollbarActionProc _ANSI_ARGS_((ControlRef theControl, ControlPartCode partCode));
105 static int ScrollbarBindProc _ANSI_ARGS_((ClientData clientData,
106 Tcl_Interp *interp, XEvent *eventPtr,
107 Tk_Window tkwin, KeySym keySym));
108 static void ScrollbarEventProc _ANSI_ARGS_(( ClientData clientData, XEvent *eventPtr));
109 static pascal void ThumbActionProc _ANSI_ARGS_((void));
110 static void UpdateControlValues _ANSI_ARGS_((MacScrollbar *macScrollPtr));
113 * The class procedure table for the scrollbar widget. Leave the proc fields
114 * initialized to NULL, which should happen automatically because of the scope
115 * at which the variable is declared.
118 Tk_ClassProcs tkpScrollbarProcs = {
119 sizeof(Tk_ClassProcs) /* size */
123 *----------------------------------------------------------------------
125 * TkpCreateScrollbar --
127 * Allocate a new TkScrollbar structure.
130 * Returns a newly allocated TkScrollbar structure.
135 *----------------------------------------------------------------------
140 Tk_Window tkwin) /* New Tk Window. */
142 MacScrollbar * macScrollPtr;
143 TkWindow *winPtr = (TkWindow *)tkwin;
145 if (scrollActionProc == NULL) {
146 scrollActionProc = NewControlActionUPP (ScrollbarActionProc);
147 thumbActionProc = NewThumbActionProc(ThumbActionProc);
150 macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar));
151 macScrollPtr->sbHandle = NULL;
152 macScrollPtr->macFlags = 0;
154 Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask|
155 StructureNotifyMask|FocusChangeMask,
156 ScrollbarEventProc, (ClientData) macScrollPtr);
158 if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
159 Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL, (ClientData)1);
160 TkCreateBindingProcedure(winPtr->mainPtr->interp,
161 winPtr->mainPtr->bindingTable,
162 (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
163 ScrollbarBindProc, NULL, NULL);
165 return (TkScrollbar *) macScrollPtr;
169 *--------------------------------------------------------------
171 * TkpDisplayScrollbar --
173 * This procedure redraws the contents of a scrollbar window.
174 * It is invoked as a do-when-idle handler, so it only runs
175 * when there's nothing else for the application to do.
181 * Information appears on the screen.
183 *--------------------------------------------------------------
188 ClientData clientData) /* Information about window. */
190 TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
191 MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
192 Tk_Window tkwin = scrollPtr->tkwin;
194 MacDrawable *macDraw;
200 if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
205 * Draw the focus or any 3D relief we may have.
207 if (scrollPtr->highlightWidth != 0) {
210 bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr,
213 if (scrollPtr->flags & GOT_FOCUS) {
214 fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr,
216 TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth,
219 TkpDrawHighlightBorder(tkwin, bgGC, bgGC, scrollPtr->highlightWidth,
223 Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
224 scrollPtr->highlightWidth, scrollPtr->highlightWidth,
225 Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
226 Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
227 scrollPtr->borderWidth, scrollPtr->relief);
230 * Set up port for drawing Macintosh control.
232 macDraw = (MacDrawable *) Tk_WindowId(tkwin);
233 destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin));
234 GetGWorld(&saveWorld, &saveDevice);
235 SetGWorld(destPort, NULL);
236 TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin));
238 if (macScrollPtr->sbHandle == NULL) {
244 WindowRef frontNonFloating;
247 r.right = r.bottom = 1;
249 minValue = MIN_SCROLLBAR_VALUE;
250 maxValue = MAX_SCROLLBAR_VALUE;
251 initialValue = (minValue + maxValue)/2;
252 procID = kControlScrollBarLiveProc;
254 windowRef = GetWindowFromPort(destPort);
255 macScrollPtr->sbHandle = NewControl(windowRef, &r, "\p",
256 false, initialValue,minValue,maxValue,
257 procID, (SInt32) scrollPtr);
260 * If we are foremost then make us active.
263 frontNonFloating = FrontNonFloatingWindow();
265 if ((windowRef == FrontWindow()) || TkpIsWindowFloating(windowRef)) {
266 macScrollPtr->macFlags |= ACTIVE;
271 * Update the control values before we draw.
273 windowRef = GetControlOwner (macScrollPtr->sbHandle);
274 UpdateControlValues(macScrollPtr);
276 if (macScrollPtr->macFlags & ACTIVE) {
277 Draw1Control(macScrollPtr->sbHandle);
278 if (macScrollPtr->macFlags & DRAW_GROW) {
279 DrawGrowIcon(windowRef);
282 HiliteControl (macScrollPtr->sbHandle, 255 );
283 Draw1Control(macScrollPtr->sbHandle);
284 if (macScrollPtr->macFlags & DRAW_GROW) {
285 DrawGrowIcon(windowRef);
286 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder,
287 Tk_Width(tkwin) - 13, Tk_Height(tkwin) - 13,
288 Tk_Width(tkwin), Tk_Height(tkwin),
293 SetGWorld(saveWorld, saveDevice);
296 scrollPtr->flags &= ~REDRAW_PENDING;
300 *----------------------------------------------------------------------
302 * TkpConfigureScrollbar --
304 * This procedure is called after the generic code has finished
305 * processing configuration options, in order to configure
306 * platform specific options.
314 *----------------------------------------------------------------------
318 TkpConfigureScrollbar(scrollPtr)
319 register TkScrollbar *scrollPtr; /* Information about widget; may or
320 * may not already have values for
326 *----------------------------------------------------------------------
328 * TkpComputeScrollbarGeometry --
330 * After changes in a scrollbar's size or configuration, this
331 * procedure recomputes various geometry information used in
332 * displaying the scrollbar.
338 * The scrollbar will be displayed differently.
340 *----------------------------------------------------------------------
344 TkpComputeScrollbarGeometry(
345 register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may
348 MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
349 int width, fieldLength, adjust = 0;
351 if (scrollPtr->highlightWidth < 0) {
352 scrollPtr->highlightWidth = 0;
354 scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
355 width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
356 : Tk_Height(scrollPtr->tkwin);
357 scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1;
358 fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
359 : Tk_Width(scrollPtr->tkwin))
360 - 2*(scrollPtr->arrowLength + scrollPtr->inset);
361 if (fieldLength < 0) {
364 scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
365 scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
368 * Adjust the slider so that some piece of it is always
369 * displayed in the scrollbar and so that it has at least
370 * a minimal width (so it can be grabbed with the mouse).
373 if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
374 scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
376 if (scrollPtr->sliderFirst < 0) {
377 scrollPtr->sliderFirst = 0;
379 if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
380 + MIN_SLIDER_LENGTH)) {
381 scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
383 if (scrollPtr->sliderLast > fieldLength) {
384 scrollPtr->sliderLast = fieldLength;
386 scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
387 scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
390 * Register the desired geometry for the window (leave enough space
391 * for the two arrows plus a minimum-size slider, plus border around
392 * the whole window, if any). Then arrange for the window to be
396 if (scrollPtr->vertical) {
397 if ((macScrollPtr->macFlags & AUTO_ADJUST) &&
398 (macScrollPtr->macFlags & (FLUSH_RIGHT|FLUSH_LEFT))) {
401 Tk_GeometryRequest(scrollPtr->tkwin,
402 scrollPtr->width + 2*scrollPtr->inset + adjust,
403 2*(scrollPtr->arrowLength + scrollPtr->borderWidth
404 + scrollPtr->inset));
406 if ((macScrollPtr->macFlags & AUTO_ADJUST) &&
407 (macScrollPtr->macFlags & (FLUSH_TOP|FLUSH_BOTTOM))) {
410 Tk_GeometryRequest(scrollPtr->tkwin,
411 2*(scrollPtr->arrowLength + scrollPtr->borderWidth
412 + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset + adjust);
414 Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
418 *----------------------------------------------------------------------
420 * TkpDestroyScrollbar --
422 * Free data structures associated with the scrollbar control.
430 *----------------------------------------------------------------------
435 TkScrollbar *scrollPtr) /* Scrollbar to destroy. */
437 MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr;
439 if (macScrollPtr->sbHandle != NULL) {
440 if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) {
441 DisposeControl(macScrollPtr->sbHandle);
442 macScrollPtr->sbHandle = NULL;
445 macScrollPtr->macFlags |= ALREADY_DEAD;
449 *--------------------------------------------------------------
451 * TkpScrollbarPosition --
453 * Determine the scrollbar element corresponding to a
457 * One of TOP_ARROW, TOP_GAP, etc., indicating which element
458 * of the scrollbar covers the position given by (x, y). If
459 * (x,y) is outside the scrollbar entirely, then OUTSIDE is
465 *--------------------------------------------------------------
469 TkpScrollbarPosition(
470 TkScrollbar *scrollPtr, /* Scrollbar widget record. */
471 int x, int y) /* Coordinates within scrollPtr's
474 MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr;
476 int length, width, tmp, inactive = false;
477 ControlPartCode part;
485 if (scrollPtr->vertical) {
486 length = Tk_Height(scrollPtr->tkwin);
487 width = Tk_Width(scrollPtr->tkwin);
492 length = Tk_Width(scrollPtr->tkwin);
493 width = Tk_Height(scrollPtr->tkwin);
496 if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
497 || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
502 * All of the calculations in this procedure mirror those in
503 * DisplayScrollbar. Be sure to keep the two consistent. On the
504 * Macintosh we use the OS call TestControl to do this mapping.
505 * For TestControl to work, the scrollbar must be active and must
506 * be in the current port.
509 destPort = TkMacOSXGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
510 SetGWorld(destPort, NULL);
511 UpdateControlValues(macScrollPtr);
512 if ( GetControlHilite(macScrollPtr->sbHandle) == 255 ) {
514 HiliteControl(macScrollPtr->sbHandle, 0 );
517 TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);
518 where.h = x0 + bounds.left;
519 where.v = y0 + bounds.top;
520 part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where);
522 HiliteControl(macScrollPtr->sbHandle, 255 );
525 case kControlUpButtonPart:
527 case kControlPageUpPart:
529 case kControlIndicatorPart:
531 case kControlPageDownPart:
533 case kControlDownButtonPart:
541 *--------------------------------------------------------------
545 * Callback procedure used by the Macintosh toolbox call
546 * TrackControl. This call is used to track the thumb of
547 * the scrollbar. Unlike the ScrollbarActionProc function
548 * this function is called once and basically takes over
549 * tracking the scrollbar from the control. This is done
550 * to avoid conflicts with what the control plans to draw.
556 * May change the display.
558 *--------------------------------------------------------------
564 register TkScrollbar *scrollPtr = activeScrollPtr;
565 register MacScrollbar *macScrollPtr = (MacScrollbar *) activeScrollPtr;
566 Tcl_DString cmdString;
567 int origValue, trackBarPin;
568 double thumbWidth, newFirstFraction, trackBarSize;
569 char valueString[40];
570 Point currentPoint = { 0, 0 };
573 MouseTrackingResult trackingResult;
576 if (scrollPtr == NULL) {
580 Tcl_DStringInit(&cmdString);
583 * First compute values that will remain constant during the tracking
584 * of the thumb. The variable trackBarSize is the length of the scrollbar
585 * minus the 2 arrows and half the width of the thumb on both sides
586 * (3 * arrowLength). The variable trackBarPin is the lower starting point
587 * of the drag region.
589 * Note: the arrowLength is equal to the thumb width of a Mac scrollbar.
592 origValue = GetControlValue(macScrollPtr->sbHandle);
593 GetControlBounds(macScrollPtr->sbHandle, &trackRect);
594 if (scrollPtr->vertical == true) {
595 trackBarSize = (double) (trackRect.bottom - trackRect.top
596 - (scrollPtr->arrowLength * 3));
597 trackBarPin = trackRect.top + scrollPtr->arrowLength
598 + (scrollPtr->arrowLength / 2);
599 InsetRect(&trackRect, -25, -113);
602 trackBarSize = (double) (trackRect.right - trackRect.left
603 - (scrollPtr->arrowLength * 3));
604 trackBarPin = trackRect.left + scrollPtr->arrowLength
605 + (scrollPtr->arrowLength / 2);
606 InsetRect(&trackRect, -113, -25);
610 * Track the mouse while the button is held down. If the mouse is moved,
611 * we calculate the value that should be passed to the "command" part of
616 err = TrackMouseLocationWithOptions(NULL,
617 kTrackMouseLocationOptionDontConsumeMouseUp,
618 kEventDurationForever,
624 && ((trackingResult == kMouseTrackingMouseDragged)
625 || (trackingResult == kMouseTrackingMouseMoved))) {
627 * Calculating this value is a little tricky. We need to calculate a
628 * value for where the thumb would be in a Motif widget (variable
629 * thumb). This value is what the "command" expects and is what will
630 * be resent to the scrollbar to update its value.
632 thumbWidth = scrollPtr->lastFraction - scrollPtr->firstFraction;
633 if (PtInRect(currentPoint, &trackRect)) {
634 if (scrollPtr->vertical == true) {
635 newFirstFraction = (1.0 - thumbWidth) *
636 ((double) (currentPoint.v - trackBarPin) / trackBarSize);
638 newFirstFraction = (1.0 - thumbWidth) *
639 ((double) (currentPoint.h - trackBarPin) / trackBarSize);
642 newFirstFraction = ((double) origValue / MAX_SCROLLBAR_DVALUE)
643 * (1.0 - thumbWidth);
645 sprintf(valueString, "%g", newFirstFraction);
646 Tcl_DStringSetLength(&cmdString, 0);
647 Tcl_DStringAppend(&cmdString, scrollPtr->command,
648 scrollPtr->commandSize);
649 Tcl_DStringAppendElement(&cmdString, "moveto");
650 Tcl_DStringAppendElement(&cmdString, valueString);
651 interp = scrollPtr->interp;
652 Tcl_Preserve((ClientData) interp);
653 Tcl_GlobalEval(interp, cmdString.string);
654 Tcl_Release((ClientData) interp);
655 Tcl_DStringSetLength(&cmdString, 0);
656 Tcl_DStringAppend(&cmdString, "update idletasks",
657 strlen("update idletasks"));
658 Tcl_Preserve((ClientData) interp);
659 Tcl_GlobalEval(interp, cmdString.string);
660 Tcl_Release((ClientData) interp);
662 } while ((err==noErr) && trackingResult!=kMouseTrackingMouseReleased );
664 Tcl_DStringFree(&cmdString);
669 *--------------------------------------------------------------
671 * ScrollbarActionProc --
673 * Callback procedure used by the Macintosh toolbox call
674 * TrackControl. This call will update the display while
675 * the scrollbar is being manipulated by the user.
681 * May change the display.
683 *--------------------------------------------------------------
688 ControlRef theControl, /* Handle to scrollbat control */
689 ControlPartCode partCode) /* Part of scrollbar that was "hit" */
691 TkScrollbar *scrollPtr = (TkScrollbar *) GetControlReference(theControl);
692 Tcl_DString cmdString;
694 Tcl_DStringInit(&cmdString);
695 Tcl_DStringAppend(&cmdString, scrollPtr->command,
696 scrollPtr->commandSize);
698 if ( partCode == kControlUpButtonPart ||
699 partCode == kControlDownButtonPart ) {
700 Tcl_DStringAppendElement(&cmdString, "scroll");
701 Tcl_DStringAppendElement(&cmdString,
702 (partCode == kControlUpButtonPart ) ? "-1" : "1");
703 Tcl_DStringAppendElement(&cmdString, "unit");
704 } else if (partCode == kControlPageUpPart || partCode == kControlPageDownPart ) {
705 Tcl_DStringAppendElement(&cmdString, "scroll");
706 Tcl_DStringAppendElement(&cmdString,
707 (partCode == kControlPageUpPart ) ? "-1" : "1");
708 Tcl_DStringAppendElement(&cmdString, "page");
710 Tcl_Preserve((ClientData) scrollPtr->interp);
711 Tcl_DStringAppend(&cmdString, "; update idletasks",
712 strlen("; update idletasks"));
713 Tcl_GlobalEval(scrollPtr->interp, cmdString.string);
714 Tcl_Release((ClientData) scrollPtr->interp);
716 Tcl_DStringFree(&cmdString);
720 *--------------------------------------------------------------
722 * ScrollbarBindProc --
724 * This procedure is invoked when the default <ButtonPress>
725 * binding on the Scrollbar bind tag fires.
731 * The event enters a modal loop.
733 *--------------------------------------------------------------
738 ClientData clientData, /* Not used. */
739 Tcl_Interp *interp, /* Interp with binding. */
740 XEvent *eventPtr, /* X event that triggered binding. */
741 Tk_Window tkwin, /* Target window for event. */
742 KeySym keySym) /* The KeySym if a key event. */
744 TkWindow *winPtr = (TkWindow*)tkwin;
745 TkScrollbar *scrollPtr = (TkScrollbar *) winPtr->instanceData;
746 MacScrollbar *macScrollPtr = (MacScrollbar *) winPtr->instanceData;
748 Tcl_Preserve((ClientData)scrollPtr);
749 macScrollPtr->macFlags |= IN_MODAL_LOOP;
751 if (eventPtr->type == ButtonPress) {
754 int part, x, y, dummy;
762 * To call Macintosh control routines we must have the port
763 * set to the window containing the control. We will then test
764 * which part of the control was hit and act accordingly.
766 destPort = TkMacOSXGetDrawablePort(Tk_WindowId(scrollPtr->tkwin));
767 GetGWorld(&saveWorld, &saveDevice);
768 SetGWorld(destPort, NULL);
769 TkMacOSXSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin));
771 TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds);
772 where.h = eventPtr->xbutton.x + bounds.left;
773 where.v = eventPtr->xbutton.y + bounds.top;
774 part = TestControl(macScrollPtr->sbHandle, where);
775 if (part == kControlIndicatorPart && scrollPtr->jump == false) {
777 * Case 1: In thumb, no jump scrolling. Call track control
778 * with the thumb action proc which will do most of the work.
779 * Set the global activeScrollPtr to the current control
780 * so the callback may have access to it.
782 activeScrollPtr = scrollPtr;
783 part = TrackControl(macScrollPtr->sbHandle, where,
784 (ControlActionUPP) thumbActionProc);
785 activeScrollPtr = NULL;
786 } else if (part == kControlIndicatorPart) {
788 * Case 2: in thumb with jump scrolling. Call TrackControl
789 * with a NULL action proc. Use the new value of the control
790 * to set update the control.
792 part = TrackControl(macScrollPtr->sbHandle, where, NULL);
793 if (part == kControlIndicatorPart) {
794 double newFirstFraction, thumbWidth;
795 Tcl_DString cmdString;
796 char valueString[TCL_DOUBLE_SPACE];
799 * The following calculation takes the new control
800 * value and maps it to what Tk needs for its variable
801 * thumb size representation.
803 thumbWidth = scrollPtr->lastFraction
804 - scrollPtr->firstFraction;
805 newFirstFraction = (1.0 - thumbWidth) *
806 ((double) GetControlValue(macScrollPtr->sbHandle) / MAX_SCROLLBAR_DVALUE);
807 sprintf(valueString, "%g", newFirstFraction);
809 Tcl_DStringInit(&cmdString);
810 Tcl_DStringAppend(&cmdString, scrollPtr->command,
811 strlen(scrollPtr->command));
812 Tcl_DStringAppendElement(&cmdString, "moveto");
813 Tcl_DStringAppendElement(&cmdString, valueString);
814 Tcl_DStringAppend(&cmdString, "; update idletasks",
815 strlen("; update idletasks"));
817 interp = scrollPtr->interp;
818 Tcl_Preserve((ClientData) interp);
819 Tcl_GlobalEval(interp, cmdString.string);
820 Tcl_Release((ClientData) interp);
821 Tcl_DStringFree(&cmdString);
823 } else if (part != 0) {
825 * Case 3: in any other part of the scrollbar. We call
826 * TrackControl with the scrollActionProc which will do
829 TrackControl(macScrollPtr->sbHandle, where, scrollActionProc);
830 HiliteControl(macScrollPtr->sbHandle, 0);
834 * The TrackControl call will "eat" the ButtonUp event. We now
835 * generate a ButtonUp event so Tk will unset implicit grabs etc.
838 XQueryPointer(NULL, None, &window, &window, &x,
839 &y, &dummy, &dummy, &state);
840 window = Tk_WindowId(scrollPtr->tkwin);
841 TkGenerateButtonEvent(x, y, window, state);
843 SetGWorld(saveWorld, saveDevice);
846 if (macScrollPtr->sbHandle && (macScrollPtr->macFlags & ALREADY_DEAD)) {
847 DisposeControl(macScrollPtr->sbHandle);
848 macScrollPtr->sbHandle = NULL;
850 macScrollPtr->macFlags &= ~IN_MODAL_LOOP;
851 Tcl_Release((ClientData)scrollPtr);
857 *--------------------------------------------------------------
859 * ScrollbarEventProc --
861 * This procedure is invoked by the Tk dispatcher for various
862 * events on scrollbars.
868 * When the window gets deleted, internal structures get
869 * cleaned up. When it gets exposed, it is redisplayed.
871 *--------------------------------------------------------------
876 ClientData clientData, /* Information about window. */
877 XEvent *eventPtr) /* Information about event. */
879 TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
880 MacScrollbar *macScrollPtr = (MacScrollbar *) clientData;
882 if (eventPtr->type == UnmapNotify) {
883 TkMacOSXSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false);
884 } else if (eventPtr->type == ActivateNotify) {
885 macScrollPtr->macFlags |= ACTIVE;
886 TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
887 } else if (eventPtr->type == DeactivateNotify) {
888 macScrollPtr->macFlags &= ~ACTIVE;
889 TkScrollbarEventuallyRedraw((ClientData) scrollPtr);
891 TkScrollbarEventProc(clientData, eventPtr);
896 *--------------------------------------------------------------
898 * UpdateControlValues --
900 * This procedure updates the Macintosh scrollbar control
901 * to display the values defined by the Tk scrollbar.
907 * The Macintosh control is updated.
909 *--------------------------------------------------------------
914 MacScrollbar *macScrollPtr) /* Scrollbar data struct. */
916 TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr;
917 Tk_Window tkwin = scrollPtr->tkwin;
918 MacDrawable * macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
919 WindowRef windowRef = GetControlOwner(macScrollPtr->sbHandle);
922 int flushRight = false;
923 int flushBottom = false;
924 Rect contrlRect, portRect;
928 * We can't use the Macintosh commands SizeControl and MoveControl as these
929 * calls will also cause a redraw which in our case will also cause
930 * flicker. To avoid this we adjust the control record directly. The
931 * Draw1Control command appears to just draw where ever the control says to
932 * draw so this seems right.
934 * NOTE: changing the control record directly may not work when
935 * Apple releases the Copland version of the MacOS (or when hell is cold).
938 contrlRect.left = macDraw->xOff + scrollPtr->inset;
939 contrlRect.top = macDraw->yOff + scrollPtr->inset;
940 contrlRect.right = macDraw->xOff + Tk_Width(tkwin) - scrollPtr->inset;
941 contrlRect.bottom = macDraw->yOff + Tk_Height(tkwin) - scrollPtr->inset;
943 SetControlBounds(macScrollPtr->sbHandle, &contrlRect );
946 * To make Tk applications look more like Macintosh applications without
947 * requiring additional work by the Tk developer we do some cute tricks.
948 * The first trick plays with the size of the widget to get it to overlap
949 * with the side of the window by one pixel (we don't do this if the placer
950 * is the geometry manager). The second trick shrinks the scrollbar if it
951 * it covers the area of the grow region ao the scrollbar can also draw
952 * the grow region if need be.
954 if (!strcmp(macDraw->winPtr->geomMgrPtr->name, "place")) {
955 macScrollPtr->macFlags &= AUTO_ADJUST;
957 macScrollPtr->macFlags |= AUTO_ADJUST;
959 GetPortBounds ( GetWindowPort ( windowRef ), &portRect );
960 if ( portRect.left == contrlRect.left ) {
961 if (macScrollPtr->macFlags & AUTO_ADJUST) {
963 SetControlBounds ( macScrollPtr->sbHandle, &contrlRect );
965 if (!(macScrollPtr->macFlags & FLUSH_LEFT)) {
966 macScrollPtr->macFlags |= FLUSH_LEFT;
967 if (scrollPtr->vertical) {
968 TkpComputeScrollbarGeometry(scrollPtr);
971 } else if (macScrollPtr->macFlags & FLUSH_LEFT) {
972 macScrollPtr->macFlags &= ~FLUSH_LEFT;
973 if (scrollPtr->vertical) {
974 TkpComputeScrollbarGeometry(scrollPtr);
978 if (portRect.top == contrlRect.top) {
979 if (macScrollPtr->macFlags & AUTO_ADJUST) {
982 if (!(macScrollPtr->macFlags & FLUSH_TOP)) {
983 macScrollPtr->macFlags |= FLUSH_TOP;
984 if (! scrollPtr->vertical) {
985 TkpComputeScrollbarGeometry(scrollPtr);
988 } else if (macScrollPtr->macFlags & FLUSH_TOP) {
989 macScrollPtr->macFlags &= ~FLUSH_TOP;
990 if (! scrollPtr->vertical) {
991 TkpComputeScrollbarGeometry(scrollPtr);
995 if (portRect.right == contrlRect.right) {
997 if (macScrollPtr->macFlags & AUTO_ADJUST) {
1000 if (!(macScrollPtr->macFlags & FLUSH_RIGHT)) {
1001 macScrollPtr->macFlags |= FLUSH_RIGHT;
1002 if (scrollPtr->vertical) {
1003 TkpComputeScrollbarGeometry(scrollPtr);
1006 } else if (macScrollPtr->macFlags & FLUSH_RIGHT) {
1007 macScrollPtr->macFlags &= ~FLUSH_RIGHT;
1008 if (scrollPtr->vertical) {
1009 TkpComputeScrollbarGeometry(scrollPtr);
1013 if (portRect.bottom == contrlRect.bottom) {
1015 if (macScrollPtr->macFlags & AUTO_ADJUST) {
1016 contrlRect.bottom++;
1018 if (!(macScrollPtr->macFlags & FLUSH_BOTTOM)) {
1019 macScrollPtr->macFlags |= FLUSH_BOTTOM;
1020 if (! scrollPtr->vertical) {
1021 TkpComputeScrollbarGeometry(scrollPtr);
1024 } else if (macScrollPtr->macFlags & FLUSH_BOTTOM) {
1025 macScrollPtr->macFlags &= ~FLUSH_BOTTOM;
1026 if (! scrollPtr->vertical) {
1027 TkpComputeScrollbarGeometry(scrollPtr);
1032 * If the scrollbar is flush against the bottom right hand corner then
1033 * it may need to draw the grow region for the window so we let the
1034 * wm code know about this scrollbar. We don't actually draw the grow
1035 * region, however, unless we are currently resizable.
1037 macScrollPtr->macFlags &= ~DRAW_GROW;
1038 if (flushBottom && flushRight) {
1039 TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, true);
1040 if (TkMacOSXResizable(macDraw->toplevel->winPtr)) {
1041 if (scrollPtr->vertical) {
1042 contrlRect.bottom -= 14;
1044 contrlRect.right -= 14;
1046 macScrollPtr->macFlags |= DRAW_GROW;
1049 TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, false);
1053 * Given the Tk parameters for the fractions of the start and
1054 * end of the thumb, the following calculation determines the
1055 * location for the fixed sized Macintosh thumb.
1057 middle = scrollPtr->firstFraction / (scrollPtr->firstFraction +
1058 (1.0 - scrollPtr->lastFraction));
1059 viewSize = (SInt32)((scrollPtr->lastFraction-scrollPtr->firstFraction)
1060 * MAX_SCROLLBAR_DVALUE);
1061 SetControlViewSize(macScrollPtr->sbHandle,viewSize);
1062 SetControlValue(macScrollPtr->sbHandle,
1063 (short) (middle * MAX_SCROLLBAR_VALUE) );
1064 contrlHilite=GetControlHilite(macScrollPtr->sbHandle);
1065 if ( contrlHilite == 0 || contrlHilite == 255) {
1066 if (scrollPtr->firstFraction == 0.0 &&
1067 scrollPtr->lastFraction == 1.0) {
1068 HiliteControl(macScrollPtr->sbHandle,255);
1070 HiliteControl(macScrollPtr->sbHandle,0);
1073 if ( !IsControlVisible (macScrollPtr -> sbHandle) ) {
1074 SetControlVisibility(macScrollPtr->sbHandle,TRUE,FALSE);