diff options
Diffstat (limited to 'macosx/tkMacOSXScrlbr.c')
-rw-r--r-- | macosx/tkMacOSXScrlbr.c | 1097 |
1 files changed, 338 insertions, 759 deletions
diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 2b5f094..af91564 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -2,69 +2,46 @@ * tkMacOSXScrollbar.c -- * * This file implements the Macintosh specific portion of the scrollbar - * widget. The Macintosh scrollbar may also draw a windows grow - * region under certain cases. + * widget. * * Copyright (c) 1996 by Sun Microsystems, Inc. - * Copyright 2001, Apple Computer, Inc. - * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ */ #include "tkMacOSXPrivate.h" #include "tkScrollbar.h" -#include "tkMacOSXDebug.h" -#define MIN_SCROLLBAR_VALUE 0 -#define SCROLLBAR_SCALING_VALUE ((double)(LONG_MAX>>1)) +/* +#ifdef TK_MAC_DEBUG +#define TK_MAC_DEBUG_SCROLLBAR +#endif +*/ /* * Declaration of Mac specific scrollbar structure. */ typedef struct MacScrollbar { - TkScrollbar info; /* Generic scrollbar info */ - ControlRef sbHandle; /* Scrollbar control */ - int macFlags; /* Various flags; see below */ - Rect eraseRect; /* Rect to erase before drawing control */ + TkScrollbar info; + NSScroller *scroller; + int variant; } MacScrollbar; -/* - * Flag bits for scrollbars on the Mac: - * - * ALREADY_DEAD: Non-zero means this scrollbar has been - * destroyed, but has not been cleaned up. - * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle - * of a modal loop. - * ACTIVE: Non-zero means this window is currently - * active (in the foreground). - */ - -#define ALREADY_DEAD 1 -#define IN_MODAL_LOOP 2 -#define ACTIVE 4 - -/* - * Globals uses locally in this file. - */ -static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */ -static ControlActionUPP thumbActionProc = NULL; /* Pointer to func. */ -static Point mouseDownPoint; /* Used to store the coordinates where the */ - /* mouse was first pressed to begin */ - /* dragging the thumb, because */ - /* ThumbActionProc can't take any args. */ - typedef struct ScrollbarMetrics { - SInt32 width, minHeight, minThumbHeight; - short topArrowHeight, bottomArrowHeight; - ControlSize size; + SInt32 width, minThumbHeight; + int minHeight, topArrowHeight, bottomArrowHeight; + NSControlSize controlSize; } ScrollbarMetrics; static ScrollbarMetrics metrics[2] = { - {15, 54, 26, 14, 14, kControlSizeNormal}, /* kThemeScrollBarMedium */ - {11, 40, 20, 10, 10, kControlSizeSmall}, /* kThemeScrollBarSmall */ + {15, 54, 26, 14, 14, NSRegularControlSize}, /* kThemeScrollBarMedium */ + {11, 40, 20, 10, 10, NSSmallControlSize}, /* kThemeScrollBarSmall */ }; /* @@ -75,35 +52,109 @@ static ScrollbarMetrics metrics[2] = { static char defWidth[TCL_INTEGER_SPACE]; /* - * Forward declarations for procedures defined later in this file: + * Declarations for functions defined in this file. */ -static pascal void ScrollbarActionProc(ControlRef theControl, - ControlPartCode partCode); -static pascal void ThumbActionProc(ControlRef theControl, - ControlPartCode partCode); -static int ScrollbarBindProc(ClientData clientData, Tcl_Interp *interp, - XEvent *eventPtr, Tk_Window tkwin, KeySym keySym); -static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); -static void UpdateControlValues(MacScrollbar *macScrollPtr); +static void UpdateScrollbarMetrics(void); +static void ScrollbarEventProc(ClientData clientData, + XEvent *eventPtr); /* - * The class procedure table for the scrollbar widget. Leave the proc fields - * initialized to NULL, which should happen automatically because of the scope - * at which the variable is declared. + * The class procedure table for the scrollbar widget. */ Tk_ClassProcs tkpScrollbarProcs = { sizeof(Tk_ClassProcs) /* size */ }; +#pragma mark TKApplication(TKScrlbr) + +#define NSAppleAquaScrollBarVariantChanged @"AppleAquaScrollBarVariantChanged" + +@implementation TKApplication(TKScrlbr) +- (void)tkScroller:(NSScroller *)scroller { + NSScrollerPart hitPart = [scroller hitPart]; + TkScrollbar *scrollPtr = (TkScrollbar *)[scroller tag]; + Tcl_DString cmdString; + Tcl_Interp *interp; + int result; + + if (!scrollPtr || !scrollPtr->command || !scrollPtr->commandSize || + hitPart == NSScrollerNoPart) { + return; + } + + Tcl_DStringInit(&cmdString); + Tcl_DStringAppend(&cmdString, scrollPtr->command, + scrollPtr->commandSize); + switch (hitPart) { + case NSScrollerKnob: + case NSScrollerKnobSlot: { + char valueString[TCL_DOUBLE_SPACE]; + + Tcl_PrintDouble(NULL, [scroller doubleValue] * + (1.0 - [scroller knobProportion]), valueString); + Tcl_DStringAppendElement(&cmdString, "moveto"); + Tcl_DStringAppendElement(&cmdString, valueString); + break; + } + case NSScrollerDecrementLine: + case NSScrollerIncrementLine: + Tcl_DStringAppendElement(&cmdString, "scroll"); + Tcl_DStringAppendElement(&cmdString, + (hitPart == NSScrollerDecrementLine) ? "-1" : "1"); + Tcl_DStringAppendElement(&cmdString, "unit"); + break; + case NSScrollerDecrementPage: + case NSScrollerIncrementPage: + Tcl_DStringAppendElement(&cmdString, "scroll"); + Tcl_DStringAppendElement(&cmdString, + (hitPart == NSScrollerDecrementPage) ? "-1" : "1"); + Tcl_DStringAppendElement(&cmdString, "page"); + break; + } + interp = scrollPtr->interp; + Tcl_Preserve(interp); + Tcl_Preserve(scrollPtr); + result = Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString), + Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL); + if (result != TCL_OK && result != TCL_CONTINUE && result != TCL_BREAK) { + Tcl_AddErrorInfo(interp, "\n (scrollbar command)"); + Tcl_BackgroundError(interp); + } + Tcl_Release(scrollPtr); + Tcl_Release(interp); + Tcl_DStringFree(&cmdString); +#ifdef TK_MAC_DEBUG_SCROLLBAR + TKLog(@"scroller %s value %f knobProportion %f", + ((TkWindow *)scrollPtr->tkwin)->pathName, [scroller doubleValue], + [scroller knobProportion]); +#endif +} +- (void)scrollBarVariantChanged:(NSNotification *)notification { +#ifdef TK_MAC_DEBUG_NOTIFICATIONS + TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); +#endif + UpdateScrollbarMetrics(); +} +- (void)_setupScrollBarNotifications { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; +#define observe(n, s) [nc addObserver:self selector:@selector(s) name:(n) object:nil] + observe(NSAppleAquaScrollBarVariantChanged, scrollBarVariantChanged:); +#undef observe + + UpdateScrollbarMetrics(); +} +@end + +#pragma mark - + /* *---------------------------------------------------------------------- * - * TkMacOSXInitScrollbarMetrics -- + * UpdateScrollbarMetrics -- * - * This function initializes the current system metrics for a - * scrollbar. + * This function retrieves the current system metrics for a scrollbar. * * Results: * None. @@ -114,35 +165,45 @@ Tk_ClassProcs tkpScrollbarProcs = { *---------------------------------------------------------------------- */ -void -TkMacOSXInitScrollbarMetrics(void) +static void +UpdateScrollbarMetrics(void) { const short height = 100, width = 50; - ThemeTrackDrawInfo info = {0, {0, 0, height, width}, 0, 1, 0, 0, - kThemeTrackShowThumb, kThemeTrackActive, 0, {{1, 0}}}; - Rect bounds; + HIThemeTrackDrawInfo info = { + .version = 0, + .bounds = {{0, 0}, {width, height}}, + .min = 0, + .max = 1, + .value = 0, + .attributes = kThemeTrackShowThumb, + .enableState = kThemeTrackActive, + .trackInfo.scrollbar = {.viewsize = 1, .pressState = 0}, + }; + CGRect bounds; Tk_ConfigSpec *specPtr; ChkErr(GetThemeMetric, kThemeMetricScrollBarWidth, &metrics[0].width); ChkErr(GetThemeMetric, kThemeMetricScrollBarMinThumbHeight, &metrics[0].minThumbHeight); info.kind = kThemeScrollBarMedium; - ChkErr(GetThemeTrackDragRect, &info, &bounds); - metrics[0].topArrowHeight = bounds.top; - metrics[0].bottomArrowHeight = height - bounds.bottom; + ChkErr(HIThemeGetTrackDragRect, &info, &bounds); + metrics[0].topArrowHeight = bounds.origin.y; + metrics[0].bottomArrowHeight = height - (bounds.origin.y + + bounds.size.height); metrics[0].minHeight = metrics[0].minThumbHeight + metrics[0].topArrowHeight + metrics[0].bottomArrowHeight; ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarWidth, &metrics[1].width); ChkErr(GetThemeMetric, kThemeMetricSmallScrollBarMinThumbHeight, &metrics[1].minThumbHeight); info.kind = kThemeScrollBarSmall; - ChkErr(GetThemeTrackDragRect, &info, &bounds); - metrics[1].topArrowHeight = bounds.top; - metrics[1].bottomArrowHeight = height - bounds.bottom; + ChkErr(HIThemeGetTrackDragRect, &info, &bounds); + metrics[1].topArrowHeight = bounds.origin.y; + metrics[1].bottomArrowHeight = height - (bounds.origin.y + + bounds.size.height); metrics[1].minHeight = metrics[1].minThumbHeight + metrics[1].topArrowHeight + metrics[1].bottomArrowHeight; - sprintf(defWidth, "%ld", metrics[0].width); + sprintf(defWidth, "%d", (int)(metrics[0].width)); for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END; specPtr++) { if (specPtr->offset == Tk_Offset(TkScrollbar, width)) { @@ -162,45 +223,49 @@ TkMacOSXInitScrollbarMetrics(void) * Returns a newly allocated TkScrollbar structure. * * Side effects: - * None. + * Registers an event handler for the widget. * *---------------------------------------------------------------------- */ TkScrollbar * TkpCreateScrollbar( - Tk_Window tkwin) /* New Tk Window. */ + Tk_Window tkwin) { - static int initialized = 0; - MacScrollbar * macScrollPtr; - TkWindow *winPtr = (TkWindow *)tkwin; + MacScrollbar *scrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar)); - if (scrollActionProc == NULL) { - scrollActionProc = NewControlActionUPP(ScrollbarActionProc); - thumbActionProc = NewControlActionUPP(ThumbActionProc); - } - if (!initialized) { - TkMacOSXInitScrollbarMetrics(); - initialized = 1; - } - macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar)); - macScrollPtr->sbHandle = NULL; - macScrollPtr->macFlags = 0; - SetRect(&macScrollPtr->eraseRect, 0, 0, 0, 0); + scrollPtr->scroller = nil; Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask| - StructureNotifyMask|FocusChangeMask, - ScrollbarEventProc, (ClientData) macScrollPtr); + StructureNotifyMask|FocusChangeMask, + ScrollbarEventProc, (ClientData) scrollPtr); - if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) { - Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL, - (ClientData)1); - TkCreateBindingProcedure(winPtr->mainPtr->interp, - winPtr->mainPtr->bindingTable, - (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>", - ScrollbarBindProc, NULL, NULL); - } - return (TkScrollbar *) macScrollPtr; + return (TkScrollbar *) scrollPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyScrollbar -- + * + * Free data structures associated with the scrollbar control. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyScrollbar( + TkScrollbar *scrollPtr) +{ + MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; + + TkMacOSXMakeCollectableAndRelease(macScrollPtr->scroller); } /* @@ -208,9 +273,9 @@ TkpCreateScrollbar( * * TkpDisplayScrollbar -- * - * This procedure redraws the contents of a scrollbar window. - * It is invoked as a do-when-idle handler, so it only runs - * when there's nothing else for the application to do. + * This procedure redraws the contents of a scrollbar window. It is + * invoked as a do-when-idle handler, so it only runs when there's + * nothing else for the application to do. * * Results: * None. @@ -227,109 +292,81 @@ TkpDisplayScrollbar( { TkScrollbar *scrollPtr = (TkScrollbar *) clientData; MacScrollbar *macScrollPtr = (MacScrollbar *) clientData; + NSScroller *scroller = macScrollPtr->scroller; Tk_Window tkwin = scrollPtr->tkwin; - CGrafPtr destPort, savePort; - Boolean portChanged; - WindowRef windowRef; + TkWindow *winPtr = (TkWindow *) tkwin; + MacDrawable *macWin = (MacDrawable *) winPtr->window; + TkMacOSXDrawingContext dc; + NSView *view = TkMacOSXDrawableView(macWin); + CGFloat viewHeight = [view bounds].size.height; + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, + .ty = viewHeight}; + NSRect frame; + double knobProportion = scrollPtr->lastFraction - scrollPtr->firstFraction; - if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { - goto done; + scrollPtr->flags &= ~REDRAW_PENDING; + if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || + !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { + return; } - - /* - * Draw the focus or any 3D relief we may have. - */ + CGContextConcatCTM(dc.context, t); if (scrollPtr->highlightWidth != 0) { GC fgGC, bgGC; - bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, - Tk_WindowId(tkwin)); - + bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin); if (scrollPtr->flags & GOT_FOCUS) { - fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, - Tk_WindowId(tkwin)); - TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth, - Tk_WindowId(tkwin)); + fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin); } else { - TkpDrawHighlightBorder(tkwin, bgGC, bgGC, scrollPtr->highlightWidth, - Tk_WindowId(tkwin)); + fgGC = bgGC; } - } - Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder, - scrollPtr->highlightWidth, scrollPtr->highlightWidth, - Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, - Tk_Height(tkwin) - 2*scrollPtr->highlightWidth, - scrollPtr->borderWidth, scrollPtr->relief); - - if (macScrollPtr->sbHandle == NULL) { - Rect r = {0, 0, 1, 1}; - - windowRef = TkMacOSXDrawableWindow(Tk_WindowId(tkwin)); - CreateScrollBarControl(windowRef, &r, 0, 0, 0, 0, true, NULL, - &(macScrollPtr->sbHandle)); - SetControlReference(macScrollPtr->sbHandle, (SInt32) scrollPtr); - - if (IsWindowActive(windowRef)) { - macScrollPtr->macFlags |= ACTIVE; + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth, + (Pixmap) macWin); + } + Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, + scrollPtr->highlightWidth, scrollPtr->highlightWidth, + Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, + Tk_Height(tkwin) - 2*scrollPtr->highlightWidth, + scrollPtr->borderWidth, scrollPtr->relief); + Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, + scrollPtr->inset, scrollPtr->inset, + Tk_Width(tkwin) - 2*scrollPtr->inset, + Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT); + if ([scroller superview] != view) { + [view addSubview:scroller]; + } + frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin), + Tk_Height(tkwin)); + frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset); + frame.origin.y = viewHeight - (frame.origin.y + frame.size.height); + NSWindow *w = [view window]; + if ([w showsResizeIndicator]) { + NSRect growBox = [view convertRect:[w _growBoxRect] fromView:nil]; + if (NSIntersectsRect(growBox, frame)) { + if (scrollPtr->vertical) { + CGFloat y = frame.origin.y; + frame.origin.y = growBox.origin.y + growBox.size.height; + frame.size.height -= frame.origin.y - y; + } else { + frame.size.width = growBox.origin.x - frame.origin.x; + } + TkMacOSXSetScrollbarGrow(winPtr, true); } } - - /* - * Update the control values before we draw. - */ - - UpdateControlValues(macScrollPtr); - - /* - * Set up port for drawing Macintosh control. - */ - destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin)); - portChanged = QDSwapPort(destPort, &savePort); - TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin)); - - /* - * Scrollbars do not erase the complete control bounds if they are wider - * than the standard width, so manually erase the extra space. - */ - - if (!EmptyRect(&macScrollPtr->eraseRect)) { - EraseRect(&macScrollPtr->eraseRect); - } - - Draw1Control(macScrollPtr->sbHandle); - - if (portChanged) { - QDSwapPort(savePort, NULL); - } - - done: - scrollPtr->flags &= ~REDRAW_PENDING; -} - -/* - *---------------------------------------------------------------------- - * - * TkpConfigureScrollbar -- - * - * This procedure is called after the generic code has finished - * processing configuration options, in order to configure - * platform specific options. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkpConfigureScrollbar(scrollPtr) - register TkScrollbar *scrollPtr; /* Information about widget; may or - * may not already have values for - * some fields. */ -{ + if (!NSEqualRects(frame, [scroller frame])) { + [scroller setFrame:frame]; + } + [scroller setEnabled:(knobProportion < 1.0 && + (scrollPtr->vertical ? frame.size.height : frame.size.width) > + metrics[macScrollPtr->variant].minHeight)]; + [scroller setDoubleValue:scrollPtr->firstFraction / (1.0 - knobProportion)]; + [scroller setKnobProportion:knobProportion]; + [scroller displayRectIgnoringOpacity:[scroller bounds]]; + TkMacOSXRestoreDrawingContext(&dc); +#ifdef TK_MAC_DEBUG_SCROLLBAR + TKLog(@"scroller %s frame %@ width %d height %d", + ((TkWindow *)scrollPtr->tkwin)->pathName, NSStringFromRect(frame), + Tk_Width(tkwin), Tk_Height(tkwin)); +#endif } /* @@ -337,9 +374,9 @@ TkpConfigureScrollbar(scrollPtr) * * TkpComputeScrollbarGeometry -- * - * After changes in a scrollbar's size or configuration, this - * procedure recomputes various geometry information used in - * displaying the scrollbar. + * After changes in a scrollbar's size or configuration, this procedure + * recomputes various geometry information used in displaying the + * scrollbar. * * Results: * None. @@ -352,18 +389,55 @@ TkpConfigureScrollbar(scrollPtr) void TkpComputeScrollbarGeometry( - register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may - * have changed. */ + register TkScrollbar *scrollPtr) + /* Scrollbar whose geometry may have + * changed. */ { - int variant, fieldLength; + MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; + NSScroller *scroller = macScrollPtr->scroller; + int width, height, variant, fieldLength; if (scrollPtr->highlightWidth < 0) { scrollPtr->highlightWidth = 0; } scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; - variant = ((scrollPtr->vertical ? Tk_Width(scrollPtr->tkwin) : - Tk_Height(scrollPtr->tkwin)) - 2 * scrollPtr->inset - < metrics[0].width) ? 1 : 0; + width = Tk_Width(scrollPtr->tkwin) - 2 * scrollPtr->inset; + height = Tk_Height(scrollPtr->tkwin) - 2 * scrollPtr->inset; + variant = ((scrollPtr->vertical ? width : height) < metrics[0].width) ? + 1 : 0; + macScrollPtr->variant = variant; + if (scroller) { + NSSize size = [scroller frame].size; + if ((size.width > size.height) ^ !scrollPtr->vertical) { + /* Orientation changed, need new scroller */ + if ([scroller superview]) { + [scroller removeFromSuperviewWithoutNeedingDisplay]; + } + TkMacOSXMakeCollectableAndRelease(scroller); + } + } + if (!scroller) { + if ((width > height) ^ !scrollPtr->vertical) { + /* -[NSScroller initWithFrame:] determines horizonalness for the + * lifetime of the scroller via isHoriz = (width > height) */ + if (scrollPtr->vertical) { + width = height; + } else if (width > 1) { + height = width - 1; + } else { + height = 1; + width = 2; + } + } + scroller = [[NSScroller alloc] initWithFrame: + NSMakeRect(0, 0, width, height)]; + macScrollPtr->scroller = TkMacOSXMakeUncollectable(scroller); + [scroller setAction:@selector(tkScroller:)]; + [scroller setTarget:NSApp]; + [scroller setTag:(NSInteger)scrollPtr]; + } + [[scroller cell] setControlSize:metrics[variant].controlSize]; + scrollPtr->arrowLength = (metrics[variant].topArrowHeight + metrics[variant].bottomArrowHeight) / 2; fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) @@ -376,9 +450,9 @@ TkpComputeScrollbarGeometry( scrollPtr->sliderLast = fieldLength * scrollPtr->lastFraction; /* - * Adjust the slider so that some piece of it is always - * displayed in the scrollbar and so that it has at least - * a minimal width (so it can be grabbed with the mouse). + * Adjust the slider so that some piece of it is always displayed in the + * scrollbar and so that it has at least a minimal width (so it can be + * grabbed with the mouse). */ if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) { @@ -401,10 +475,9 @@ TkpComputeScrollbarGeometry( metrics[variant].bottomArrowHeight; /* - * Register the desired geometry for the window (leave enough space - * for the two arrows plus a minimum-size slider, plus border around - * the whole window, if any). Then arrange for the window to be - * redisplayed. + * Register the desired geometry for the window (leave enough space for + * the two arrows plus a minimum-size slider, plus border around the whole + * window, if any). Then arrange for the window to be redisplayed. */ if (scrollPtr->vertical) { @@ -419,14 +492,22 @@ TkpComputeScrollbarGeometry( 2 * scrollPtr->inset); } Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); +#ifdef TK_MAC_DEBUG_SCROLLBAR + TKLog(@"scroller %s bounds %@ width %d height %d inset %d borderWidth %d", + ((TkWindow *)scrollPtr->tkwin)->pathName, + NSStringFromRect([scroller bounds]), + width, height, scrollPtr->inset, scrollPtr->borderWidth); +#endif } /* *---------------------------------------------------------------------- * - * TkpDestroyScrollbar -- + * TkpConfigureScrollbar -- * - * Free data structures associated with the scrollbar control. + * This procedure is called after the generic code has finished + * processing configuration options, in order to configure platform + * specific options. * * Results: * None. @@ -438,18 +519,11 @@ TkpComputeScrollbarGeometry( */ void -TkpDestroyScrollbar( - TkScrollbar *scrollPtr) /* Scrollbar to destroy. */ +TkpConfigureScrollbar( + register TkScrollbar *scrollPtr) + /* Information about widget; may or may not + * already have values for some fields. */ { - MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr; - - if (macScrollPtr->sbHandle != NULL) { - if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) { - DisposeControl(macScrollPtr->sbHandle); - macScrollPtr->sbHandle = NULL; - } - } - macScrollPtr->macFlags |= ALREADY_DEAD; } /* @@ -457,14 +531,12 @@ TkpDestroyScrollbar( * * TkpScrollbarPosition -- * - * Determine the scrollbar element corresponding to a - * given position. + * Determine the scrollbar element corresponding to a given position. * * Results: - * One of TOP_ARROW, TOP_GAP, etc., indicating which element - * of the scrollbar covers the position given by (x, y). If - * (x,y) is outside the scrollbar entirely, then OUTSIDE is - * returned. + * One of TOP_ARROW, TOP_GAP, etc., indicating which element of the + * scrollbar covers the position given by (x, y). If (x,y) is outside the + * scrollbar entirely, then OUTSIDE is returned. * * Side effects: * None. @@ -474,395 +546,32 @@ TkpDestroyScrollbar( int TkpScrollbarPosition( - TkScrollbar *scrollPtr, /* Scrollbar widget record. */ - int x, int y) /* Coordinates within scrollPtr's - * window. */ + register TkScrollbar *scrollPtr, + /* Scrollbar widget record. */ + int x, int y) /* Coordinates within scrollPtr's window. */ { - MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - CGrafPtr destPort, savePort; - Boolean portChanged; - int inactive = 0; - ControlPartCode part; - Point where = {y, x}; - Rect bounds; - - if ((x < scrollPtr->inset) || (x >= (Tk_Width(scrollPtr->tkwin) - - scrollPtr->inset)) || (y < scrollPtr->inset) || - (y >= (Tk_Height(scrollPtr->tkwin) - scrollPtr->inset))) { + NSScroller *scroller = ((MacScrollbar *) scrollPtr)->scroller; + MacDrawable *macWin = (MacDrawable *) + ((TkWindow *) scrollPtr->tkwin)->window; + NSView *view = TkMacOSXDrawableView(macWin); + + switch ([scroller testPart:NSMakePoint(macWin->xOff + x, + [view bounds].size.height - (macWin->yOff + y))]) { + case NSScrollerDecrementLine: + return TOP_ARROW; + case NSScrollerDecrementPage: + return TOP_GAP; + case NSScrollerKnob: + return SLIDER; + case NSScrollerIncrementPage: + return BOTTOM_GAP; + case NSScrollerIncrementLine: + return BOTTOM_ARROW; + case NSScrollerKnobSlot: + case NSScrollerNoPart: + default: return OUTSIDE; } - - /* - * All of the calculations in this procedure mirror those in - * DisplayScrollbar. Be sure to keep the two consistent. On the - * Macintosh we use the OS call TestControl to do this mapping. - * For TestControl to work, the scrollbar must be active and must - * be in the current port. - */ - - destPort = TkMacOSXGetDrawablePort(Tk_WindowId(scrollPtr->tkwin)); - portChanged = QDSwapPort(destPort, &savePort); - UpdateControlValues(macScrollPtr); - if (!IsControlActive(macScrollPtr->sbHandle)) { - inactive = true; - ActivateControl(macScrollPtr->sbHandle); - } - TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds); - where.h += bounds.left; - where.v += bounds.top; - part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where); - if (inactive) { - DeactivateControl(macScrollPtr->sbHandle); - } - if (portChanged) { - QDSwapPort(savePort, NULL); - } - switch (part) { - case kAppearancePartUpButton: - return TOP_ARROW; - case kAppearancePartPageUpArea: - return TOP_GAP; - case kAppearancePartIndicator: - return SLIDER; - case kAppearancePartPageDownArea: - return BOTTOM_GAP; - case kAppearancePartDownButton: - return BOTTOM_ARROW; - default: - return OUTSIDE; - } -} - -/* - *-------------------------------------------------------------- - * - * ThumbActionProc -- - * - * Callback procedure used by the Macintosh toolbox call - * HandleControlClick. This call is used to track the - * thumb of the scrollbar. Unlike the - * ScrollbarActionProc function this function is called - * once and basically takes over tracking the scrollbar - * from the control. This is done to avoid conflicts with - * what the control plans to draw. - * - * Results: - * None. - * - * Side effects: - * May change the display. - * - *-------------------------------------------------------------- - */ - -static pascal void -ThumbActionProc(ControlRef theControl, ControlPartCode partCode) -{ - TkScrollbar *scrollPtr = (TkScrollbar *)(intptr_t)GetControlReference( - theControl); - MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - Tcl_DString cmdString; - int origValue, variant; - short trackBarSize; - double oldFirstFraction, newFirstFraction; - char valueString[40]; - Point currentPoint = { 0, 0 }; - Rect trackRect; - Tcl_Interp *interp; - MouseTrackingResult trackingResult; - OSStatus err; - - if (scrollPtr == NULL) { - return; - } - - Tcl_DStringInit(&cmdString); - origValue = GetControl32BitValue(macScrollPtr->sbHandle); - GetControlBounds(macScrollPtr->sbHandle, &trackRect); - - if (scrollPtr->vertical) { - variant = (trackRect.right - trackRect.left) < metrics[0].width ? 1 : 0; - trackBarSize = trackRect.bottom - trackRect.top - - metrics[variant].topArrowHeight - - metrics[variant].bottomArrowHeight; - InsetRect(&trackRect, -25, -113); - } else { - variant = (trackRect.bottom - trackRect.top) < metrics[0].width ? 1 : 0; - trackBarSize = trackRect.right - trackRect.left - - metrics[variant].topArrowHeight - - metrics[variant].bottomArrowHeight; - InsetRect(&trackRect, -113, -25); - } - - /* - * Track the mouse while the button is held down. If the mouse is moved, - * we calculate the value that should be passed to the "command" part of - * the scrollbar. Since the mouse may move a distance too small to - * cause a change to the first fraction, each calculation must be done - * versus what the first fraction was when the mouse button was - * initially pressed. Otherwise, moving the mouse too slowly will - * cause the calculated fraction delta to be zero and the scrollbar - * won't respond. - */ - - oldFirstFraction = scrollPtr->firstFraction; - - TkMacOSXTrackingLoop(1); - do { - err = ChkErr(TrackMouseLocationWithOptions, NULL, - kTrackMouseLocationOptionDontConsumeMouseUp, - kEventDurationForever, ¤tPoint, NULL, &trackingResult); - if ((err == noErr) && ((trackingResult == kMouseTrackingMouseDragged) - || (trackingResult == kMouseTrackingMouseMoved))) { - - /* - * Calculate where the scrollbar should move to, based on - * where the mouse button was pressed and where the scrollbar - * initially was at that time. Note that PtInRect() will - * return false if currentPoint or trackRect are not in - * is not in current graphics port, which may happen if any - * of the waiting idle events change the port (e.g. with - * SetPort()) but fail to restore it before returning and the - * scrollbar will lock in place. - */ - newFirstFraction = oldFirstFraction; - if (PtInRect(currentPoint, &trackRect)) { - short pixDiff; - - if (scrollPtr->vertical) { - pixDiff = currentPoint.v - mouseDownPoint.v; - } else { - pixDiff = currentPoint.h - mouseDownPoint.h; - } - newFirstFraction += (double)pixDiff / trackBarSize; - if (newFirstFraction > 1.0) { - newFirstFraction = 1.0; - } else if (newFirstFraction < 0.0) { - newFirstFraction = 0.0; - } - } - - /* - * Move the scrollbar thumb to the new first fraction given - * its position when initially pressed and how far the mouse - * has moved. Process waiting idle tasks afterward to allow - * for the display to update. - */ - - sprintf(valueString, "%g", newFirstFraction); - Tcl_DStringSetLength(&cmdString, 0); - Tcl_DStringAppend(&cmdString, scrollPtr->command, - scrollPtr->commandSize); - Tcl_DStringAppendElement(&cmdString, "moveto"); - Tcl_DStringAppendElement(&cmdString, valueString); - interp = scrollPtr->interp; - Tcl_Preserve((ClientData) interp); - Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString), - Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL); - Tcl_Release((ClientData) interp); - TkMacOSXRunTclEventLoop(); - } - } while ((err == noErr) && trackingResult != kMouseTrackingMouseReleased); - TkMacOSXTrackingLoop(0); - Tcl_DStringFree(&cmdString); - return; -} - -/* - *-------------------------------------------------------------- - * - * ScrollbarActionProc -- - * - * Callback procedure used by the Macintosh toolbox call - * HandleControlClick. This call will update the display - * while the scrollbar is being manipulated by the user. - * - * Results: - * None. - * - * Side effects: - * May change the display. - * - *-------------------------------------------------------------- - */ - -static pascal void -ScrollbarActionProc( - ControlRef theControl, /* Handle to scrollbat control */ - ControlPartCode partCode) /* Part of scrollbar that was "hit" */ -{ - TkScrollbar *scrollPtr = (TkScrollbar *)(intptr_t)GetControlReference( - theControl); - MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; - Tcl_DString cmdString; - - Tcl_DStringInit(&cmdString); - Tcl_DStringAppend(&cmdString, scrollPtr->command, - scrollPtr->commandSize); - - if ( partCode == kAppearancePartUpButton || - partCode == kAppearancePartDownButton ) { - Tcl_DStringAppendElement(&cmdString, "scroll"); - Tcl_DStringAppendElement(&cmdString, - (partCode == kAppearancePartUpButton) ? "-1" : "1"); - Tcl_DStringAppendElement(&cmdString, "unit"); - } else if (partCode == kAppearancePartPageUpArea || - partCode == kAppearancePartPageDownArea ) { - Tcl_DStringAppendElement(&cmdString, "scroll"); - Tcl_DStringAppendElement(&cmdString, - (partCode == kAppearancePartPageUpArea) ? "-1" : "1"); - Tcl_DStringAppendElement(&cmdString, "page"); - } else if (partCode == kAppearancePartIndicator) { - char valueString[TCL_DOUBLE_SPACE]; - - sprintf(valueString, "%g", - (GetControl32BitValue(macScrollPtr->sbHandle) - - MIN_SCROLLBAR_VALUE) / SCROLLBAR_SCALING_VALUE); - Tcl_DStringAppendElement(&cmdString, "moveto"); - Tcl_DStringAppendElement(&cmdString, valueString); - } - Tcl_Preserve((ClientData) scrollPtr->interp); - Tcl_EvalEx(scrollPtr->interp, Tcl_DStringValue(&cmdString), - Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL); - Tcl_Release((ClientData) scrollPtr->interp); - Tcl_DStringFree(&cmdString); - TkMacOSXRunTclEventLoop(); -} - -/* - *-------------------------------------------------------------- - * - * ScrollbarBindProc -- - * - * This procedure is invoked when the default <ButtonPress> - * binding on the Scrollbar bind tag fires. - * - * Results: - * None. - * - * Side effects: - * The event enters a modal loop. - * - *-------------------------------------------------------------- - */ - -static int -ScrollbarBindProc( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interp with binding. */ - XEvent *eventPtr, /* X event that triggered binding. */ - Tk_Window tkwin, /* Target window for event. */ - KeySym keySym) /* The KeySym if a key event. */ -{ - TkWindow *winPtr = (TkWindow*)tkwin; - TkScrollbar *scrollPtr = (TkScrollbar *) winPtr->instanceData; - MacScrollbar *macScrollPtr = (MacScrollbar *) winPtr->instanceData; - - Tcl_Preserve((ClientData)scrollPtr); - macScrollPtr->macFlags |= IN_MODAL_LOOP; - - if (eventPtr->type == ButtonPress) { - Point where; - Rect bounds; - ControlPartCode part; - CGrafPtr destPort, savePort; - Boolean portChanged; - Window window; - - /* - * To call Macintosh control routines we must have the port - * set to the window containing the control. We will then test - * which part of the control was hit and act accordingly. - */ - destPort = TkMacOSXGetDrawablePort(Tk_WindowId(scrollPtr->tkwin)); - portChanged = QDSwapPort(destPort, &savePort); - TkMacOSXSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin)); - - TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds); - where.h = eventPtr->xbutton.x + bounds.left; - where.v = eventPtr->xbutton.y + bounds.top; - part = TestControl(macScrollPtr->sbHandle, where); - TkMacOSXTrackingLoop(1); - if (part == kAppearancePartIndicator && scrollPtr->jump == false) { - /* - * Case 1: In thumb, no jump scrolling. Call track control - * with the thumb action proc which will do most of the work. - */ - mouseDownPoint.h = where.h; - mouseDownPoint.v = where.v; - part = HandleControlClick(macScrollPtr->sbHandle, where, - TkMacOSXModifierState(), thumbActionProc); - } else if (part == kAppearancePartIndicator) { - /* - * Case 2: in thumb with jump scrolling. Call HandleControlClick - * with a NULL action proc. Use the new value of the control - * to set update the control. - */ - part = HandleControlClick(macScrollPtr->sbHandle, where, - TkMacOSXModifierState(), NULL); - if (part == kAppearancePartIndicator) { - Tcl_DString cmdString; - char valueString[TCL_DOUBLE_SPACE]; - - sprintf(valueString, "%g", - (GetControl32BitValue(macScrollPtr->sbHandle) - - MIN_SCROLLBAR_VALUE) / SCROLLBAR_SCALING_VALUE); - Tcl_DStringInit(&cmdString); - Tcl_DStringAppend(&cmdString, scrollPtr->command, - strlen(scrollPtr->command)); - Tcl_DStringAppendElement(&cmdString, "moveto"); - Tcl_DStringAppendElement(&cmdString, valueString); - - interp = scrollPtr->interp; - Tcl_Preserve((ClientData) interp); - Tcl_EvalEx(interp, Tcl_DStringValue(&cmdString), - Tcl_DStringLength(&cmdString), TCL_EVAL_GLOBAL); - Tcl_Release((ClientData) interp); - Tcl_DStringFree(&cmdString); - TkMacOSXRunTclEventLoop(); - } - } else if (part != 0) { - /* - * Case 3: in any other part of the scrollbar. We call - * HandleControlClick with the scrollActionProc which will do - * most all the work. - */ - HandleControlClick(macScrollPtr->sbHandle, where, - TkMacOSXModifierState(), scrollActionProc); - /* - * Workaround for Carbon bug where the scrollbar down arrow - * sometimes gets "stuck" after the mousebutton has been released. - */ - if (scrollPtr->tkwin) { - TkMacOSXSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin)); - } - Draw1Control(macScrollPtr->sbHandle); - } - TkMacOSXTrackingLoop(0); - - /* - * The HandleControlClick call will "eat" the ButtonUp event. We now - * generate a ButtonUp event so Tk will unset implicit grabs etc. - */ - - if (scrollPtr->tkwin) { - window = Tk_WindowId(scrollPtr->tkwin); - TkGenerateButtonEventForXPointer(window); - } - - if (portChanged) { - QDSwapPort(savePort, NULL); - } - } - - if (macScrollPtr->sbHandle && (macScrollPtr->macFlags & ALREADY_DEAD)) { - DisposeControl(macScrollPtr->sbHandle); - macScrollPtr->sbHandle = NULL; - } - macScrollPtr->macFlags &= ~IN_MODAL_LOOP; - Tcl_Release((ClientData)scrollPtr); - - return TCL_OK; } /* @@ -870,15 +579,15 @@ ScrollbarBindProc( * * ScrollbarEventProc -- * - * This procedure is invoked by the Tk dispatcher for various - * events on scrollbars. + * This procedure is invoked by the Tk dispatcher for various events on + * scrollbars. * * Results: * None. * * Side effects: - * When the window gets deleted, internal structures get - * cleaned up. When it gets exposed, it is redisplayed. + * When the window gets deleted, internal structures get cleaned up. When + * it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ @@ -889,155 +598,25 @@ ScrollbarEventProc( XEvent *eventPtr) /* Information about event. */ { TkScrollbar *scrollPtr = (TkScrollbar *) clientData; - MacScrollbar *macScrollPtr = (MacScrollbar *) clientData; - if (eventPtr->type == UnmapNotify) { + switch (eventPtr->type) { + case UnmapNotify: TkMacOSXSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false); - } else if (eventPtr->type == ActivateNotify) { - macScrollPtr->macFlags |= ACTIVE; + break; + case ActivateNotify: + case DeactivateNotify: TkScrollbarEventuallyRedraw((ClientData) scrollPtr); - } else if (eventPtr->type == DeactivateNotify) { - macScrollPtr->macFlags &= ~ACTIVE; - TkScrollbarEventuallyRedraw((ClientData) scrollPtr); - } else { + break; + default: TkScrollbarEventProc(clientData, eventPtr); } } /* - *-------------------------------------------------------------- - * - * UpdateControlValues -- - * - * This procedure updates the Macintosh scrollbar control - * to display the values defined by the Tk scrollbar. - * - * Results: - * None. - * - * Side effects: - * The Macintosh control is updated. - * - *-------------------------------------------------------------- + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: */ - -static void -UpdateControlValues( - MacScrollbar *macScrollPtr) /* Scrollbar data struct. */ -{ - TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr; - Tk_Window tkwin = scrollPtr->tkwin; - MacDrawable * macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); - double dViewSize; - Rect contrlRect, portRect; - int variant, active; - short width, height; - - contrlRect.left = macDraw->xOff + scrollPtr->inset; - contrlRect.top = macDraw->yOff + scrollPtr->inset; - contrlRect.right = macDraw->xOff + Tk_Width(tkwin) - scrollPtr->inset; - contrlRect.bottom = macDraw->yOff + Tk_Height(tkwin) - scrollPtr->inset; - - GetPortBounds (GetWindowPort(GetControlOwner(macScrollPtr->sbHandle)), - &portRect); - - /* - * If the scrollbar is flush against the bottom right hand corner then - * we leave space to draw the grow region for the window. - */ - if (portRect.bottom == contrlRect.bottom && - portRect.right == contrlRect.right) { - TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, true); - if (macDraw->toplevel && - TkMacOSXResizable(macDraw->toplevel->winPtr)) { - int growSize; - - switch (TkMacOSXWindowClass(macDraw->toplevel->winPtr)) { - case kFloatingWindowClass: - case kUtilityWindowClass: - growSize = metrics[1].width - 1; - break; - case kDocumentWindowClass: - case kMovableAlertWindowClass: - case kMovableModalWindowClass: - default: - growSize = metrics[0].width - 1; - break; - } - if (scrollPtr->vertical) { - contrlRect.bottom -= growSize; - } else { - contrlRect.right -= growSize; - } - } - } else { - TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, false); - } - - if (IsControlVisible (macScrollPtr->sbHandle)) { - SetControlVisibility(macScrollPtr->sbHandle, false, false); - } - - if (scrollPtr->vertical) { - width = contrlRect.right - contrlRect.left; - height = contrlRect.bottom - contrlRect.top; - } else { - width = contrlRect.bottom - contrlRect.top; - height = contrlRect.right - contrlRect.left; - } - variant = width < metrics[0].width ? 1 : 0; - SetControlData(macScrollPtr->sbHandle, kControlEntireControl, - kControlSizeTag, sizeof(ControlSize), - &(metrics[variant].size)); - - macScrollPtr->eraseRect = contrlRect; - if (scrollPtr->vertical) { - macScrollPtr->eraseRect.left += metrics[variant].width; - } else { - macScrollPtr->eraseRect.top += metrics[variant].width; - } - - /* - * Ensure we set scrollbar control bounds only once all size - * adjustments have been computed. - */ - - SetControlBounds(macScrollPtr->sbHandle, &contrlRect); - - /* - * Given the Tk parameters for the fractions of the start and - * end of the thumb, the following calculation determines the - * location for the Macintosh thumb. - * The Aqua scroll control works as follows. - * The scrollbar's value is the position of the left (or top) side of - * the view area in the content area being scrolled. - * The maximum value of the control is therefore the dimension of - * the content area less the size of the view area. - * Since these values are all integers, and Tk gives the thumb position - * as fractions, we have introduced a scaling factor. - */ - - dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction) - * SCROLLBAR_SCALING_VALUE; - SetControl32BitMinimum(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE); - SetControl32BitMaximum(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE + - SCROLLBAR_SCALING_VALUE - dViewSize); - SetControlViewSize(macScrollPtr->sbHandle, dViewSize); - SetControl32BitValue(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE + - SCROLLBAR_SCALING_VALUE * scrollPtr->firstFraction); - - if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0) - || height <= metrics[variant].minHeight) { - /* Disable scrollbar */ - SetControl32BitMaximum(macScrollPtr->sbHandle, MIN_SCROLLBAR_VALUE); - } - active = ((macScrollPtr->macFlags & ACTIVE) != 0); - if (active != IsControlActive(macScrollPtr->sbHandle)) { - if (active) { - ActivateControl(macScrollPtr->sbHandle); - } else { - DeactivateControl(macScrollPtr->sbHandle); - } - } - SetControlVisibility(macScrollPtr->sbHandle, true, false); -} |