diff options
author | das <das> | 2002-08-31 06:12:19 (GMT) |
---|---|---|
committer | das <das> | 2002-08-31 06:12:19 (GMT) |
commit | e947c1d0d386b229818958dc12ea0cc20e4ec582 (patch) | |
tree | 303845583d22d9e5e5f3f53edf451167cb5847e6 /macosx/tkMacOSXScrlbr.c | |
parent | 62d94160aed093a9505d60181a1509e69bd02bb6 (diff) | |
download | tk-e947c1d0d386b229818958dc12ea0cc20e4ec582.zip tk-e947c1d0d386b229818958dc12ea0cc20e4ec582.tar.gz tk-e947c1d0d386b229818958dc12ea0cc20e4ec582.tar.bz2 |
*** macosx-8-4-branch merged into the mainline [tcl patch #602770] ***macosx_8_4_merge_2002_08_31_trunk
* generic/tk.decls:
* generic/tkInt.decls: added new "aqua" specific entries to the
stubs tables. Changed all "unix" entries to "x11" to allow us to
distinguish and build both "aqua" on MacOSX and "x11" on MacOSX.
* generic/tk.h: added a #ifnded RESOURCE_INCLUDED so that tk.h can
be passed to the resource compiler.
* generic/tkCmds.c (Tk_TkObjCmd): added [tk windowingsystem]
subcommand: returns "x11" when running on X11, "win32" on Windows,
"classic" on MacOS9 and "aqua" on MacOSX Aqua (i.e. Carbon)
* generic/tkFont.c (TkFontGetFirstTextLayout): new private function
returning the first chunk of a Tk_TextLayout, i.e. until the first
font change on the first line (or the whole first line if there is
no such font change).
* generic/tkMain.c: made Tcl_ThreadDataKey static
* library/demos/puzzle.tcl: fixed button metrics for aqua
* tests/cursor.test: check for presence of arrow cursor instead of
heart cursor
* xlib/xcolors.c: changed xColors static initialization to more
standard C
* macosx/Wish.pbproj/jingham.pbxuser (new):
* macosx/Wish.pbproj/project.pbxproj (new): project for Apple's
ProjectBuilder IDE.
* macosx/Makefile (new): simple makefile for building the project
from the command line via the ProjectBuilder tool 'pbxbuild'.
* macosx/tkMacOSXAppInit.c (new): macosx specific AppInit looking
for a AppMain.tcl file in its bundled Resources/Scripts folder. If
present, argv[1] is set to that file and the Scripts folder is
added to the auto_path. This allows tk apps to embed scripts within
their bundle directory structure.
* macosx/tkMacOSXInit.c (new): macosx adapted version of
tkUnixInit.c: we initialize & cache the Carbon native encoding
(e.g. 'macRoman') and try to find the tk script library files
inside Tk packaged as a framework.
* macosx/tkMacOSXNotify.c (new): new macosx specific merged
Carbon/select-based notifier.
* macosx/tkMacOSXEvent.c (new):
* macosx/tkMacOSXEvent.h (new):
* macosx/tkMacOSXKeyEvent.c (new):
* macosx/tkMacOSXMouseEvent.c (new):
* macosx/tkMacOSXWindowEvent.c (new): new macosx specific event
handling functionality.
* macosx/tkMacOSX.h (new):
* macosx/tkMacOSXBitmap.c (new):
* macosx/tkMacOSXButton.c (new):
* macosx/tkMacOSXClipboard.c (new):
* macosx/tkMacOSXColor.c (new):
* macosx/tkMacOSXConfig.c (new):
* macosx/tkMacOSXCursor.c (new):
* macosx/tkMacOSXDefault.h (new):
* macosx/tkMacOSXDialog.c (new):
* macosx/tkMacOSXDraw.c (new):
* macosx/tkMacOSXEmbed.c (new):
* macosx/tkMacOSXFont.c (new):
* macosx/tkMacOSXHLEvents.c (new):
* macosx/tkMacOSXInt.h (new):
* macosx/tkMacOSXKeyboard.c (new):
* macosx/tkMacOSXMenu.c (new):
* macosx/tkMacOSXMenubutton.c (new):
* macosx/tkMacOSXMenus.c (new):
* macosx/tkMacOSXPort.h (new):
* macosx/tkMacOSXRegion.c (new):
* macosx/tkMacOSXScale.c (new):
* macosx/tkMacOSXScrlbr.c (new):
* macosx/tkMacOSXSubwindows.c (new):
* macosx/tkMacOSXTest.c (new):
* macosx/tkMacOSXUtil.c (new):
* macosx/tkMacOSXUtil.h (new):
* macosx/tkMacOSXWm.c (new):
* macosx/tkMacOSXWm.h (new):
* macosx/tkMacOSXXStubs.c (new): macosx ports of classic mac Tk
implementation in tk/mac.
* macosx/tkMacOSXSend.c (new): only send to local interp
implemented currently.
* macosx/tkMacOSXDebug.h (new):
* macosx/tkMacOSXDebug.c (new): new macosx specific functions for
debugging MacOS events, regions, etc.
* macosx/tkAboutDlg.r (new):
* macosx/tkMacOSXApplication.r (new):
* macosx/tkMacOSXCursors.r (new):
* macosx/tkMacOSXLibrary.r (new):
* macosx/tkMacOSXMenu.r (new):
* macosx/tkMacOSXResource.r (new):
* macosx/tkMacOSXXCursors.r (new):
* macosx/tclets.r (new): sources for Rez resource compiler.
* macosx/Wish.icns (new): Wish application icon.
* generic/tk.h:
* generic/default.h:
* generic/tkBind.c:
* generic/tkCmds.c:
* generic/tkGrab.c:
* generic/tkPointer.c:
* generic/tkPort.h:
* generic/tkSelect.c:
* generic/tkStubLib.c:
* generic/tkTest.c:
* generic/tkText.c:
* generic/tkWindow.c:
* unix/tkUnix3d.c:
* xlib/xgc.c:
* xlib/X11/X.h:
* xlib/X11/Xlib.h:
* xlib/X11/Xutil.h: added #includes and #ifdefs for macosx
* library/bgerror.tcl:
* library/button.tcl:
* library/console.tcl:
* library/dialog.tcl:
* library/entry.tcl:
* library/listbox.tcl:
* library/menu.tcl:
* library/msgbox.tcl:
* library/scrlbar.tcl:
* library/spinbox.tcl:
* library/text.tcl:
* library/tk.tcl:
* library/demos/menu.tcl:
* library/demos/menubu.tcl:
* library/demos/widget: check [tk windowingsystem] instead of
and/or in addition to $tcl_platform(platform).
* generic/tkInt.h:
* mac/tkMacBitmap.c:
* mac/tkMacWm.c: added missing CONSTification
* generic/tkIntDecls.h:
* generic/tkIntPlatDecls.h:
* generic/tkIntXlibDecls.h:
* generic/tkPlatDecls.h:
* generic/tkStubInit.c: regen
Diffstat (limited to 'macosx/tkMacOSXScrlbr.c')
-rw-r--r-- | macosx/tkMacOSXScrlbr.c | 1076 |
1 files changed, 1076 insertions, 0 deletions
diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c new file mode 100644 index 0000000..12b4443 --- /dev/null +++ b/macosx/tkMacOSXScrlbr.c @@ -0,0 +1,1076 @@ +/* + * 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. + * + * Copyright (c) 1996 by Sun Microsystems, Inc. + * Copyright 2001, Apple Computer, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkMacOSXScrlbr.c,v 1.2 2002/08/31 06:12:30 das Exp $ + */ + +#include "tkScrollbar.h" +#include "tkMacOSXInt.h" + +#include <Carbon/Carbon.h> + +#include "tkMacOSXDebug.h" +/* + * The following definitions should really be in MacOS + * header files. They are included here as this is the only + * file that needs the declarations. + */ +typedef pascal void (*ThumbActionFunc)(void); + +typedef ThumbActionFunc ThumbActionUPP; + +enum { + uppThumbActionProcInfo = kPascalStackBased +}; + +#define NewThumbActionProc(userRoutine) ((ThumbActionUPP) (userRoutine)) + +/* + * Minimum slider length, in pixels (designed to make sure that the slider + * is always easy to grab with the mouse). + */ + +#define MIN_SLIDER_LENGTH 5 +#define MIN_SCROLLBAR_VALUE 0 +#define MAX_SCROLLBAR_VALUE 1000 +#define MAX_SCROLLBAR_DVALUE 1000.0 + +/* + * Declaration of Windows specific scrollbar structure. + */ + +typedef struct MacScrollbar { + TkScrollbar info; /* Generic scrollbar info */ + ControlRef sbHandle; /* Opaque handle to the Scrollbar contol struct */ + int macFlags; /* Various flags; see below */ +} MacScrollbar; + +/* Handle to the Scrollbar control structure */ + + +/* + * 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). + * FLUSH_TOP: Flush with top of Mac window. + * FLUSH_BOTTOM: Flush with bottom of Mac window. + * FLUSH_RIGHT: Flush with right of Mac window. + * FLUSH_LEFT: Flush with left of Mac window. + * SCROLLBAR_GROW: Non-zero means this window draws the grow + * region for the toplevel window. + * AUTO_ADJUST: Non-zero means we automatically adjust + * the size of the widget to align correctly + * along a Mac window. + * DRAW_GROW: Non-zero means we draw the grow region. + */ + +#define ALREADY_DEAD 1 +#define IN_MODAL_LOOP 2 +#define ACTIVE 4 +#define FLUSH_TOP 8 +#define FLUSH_BOTTOM 16 +#define FLUSH_RIGHT 32 +#define FLUSH_LEFT 64 +#define SCROLLBAR_GROW 128 +#define AUTO_ADJUST 256 +#define DRAW_GROW 512 + +/* + * Globals uses locally in this file. + */ +static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */ +static ThumbActionUPP thumbActionProc = NULL; /* Pointer to func. */ +static TkScrollbar *activeScrollPtr = NULL; /* Non-null when in thumb */ + /* proc. */ +/* + * Forward declarations for procedures defined later in this file: + */ + +static pascal void ScrollbarActionProc _ANSI_ARGS_((ControlRef theControl, ControlPartCode partCode)); +static int ScrollbarBindProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, XEvent *eventPtr, + Tk_Window tkwin, KeySym keySym)); +static void ScrollbarEventProc _ANSI_ARGS_(( ClientData clientData, XEvent *eventPtr)); +static pascal void ThumbActionProc _ANSI_ARGS_((void)); +static void UpdateControlValues _ANSI_ARGS_((MacScrollbar *macScrollPtr)); + +/* + * 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. + */ + +Tk_ClassProcs tkpScrollbarProcs = { + sizeof(Tk_ClassProcs) /* size */ +}; + +/* + *---------------------------------------------------------------------- + * + * TkpCreateScrollbar -- + * + * Allocate a new TkScrollbar structure. + * + * Results: + * Returns a newly allocated TkScrollbar structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkScrollbar * +TkpCreateScrollbar( + Tk_Window tkwin) /* New Tk Window. */ +{ + MacScrollbar * macScrollPtr; + TkWindow *winPtr = (TkWindow *)tkwin; + + if (scrollActionProc == NULL) { + scrollActionProc = NewControlActionUPP (ScrollbarActionProc); + thumbActionProc = NewThumbActionProc(ThumbActionProc); + } + + macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar)); + macScrollPtr->sbHandle = NULL; + macScrollPtr->macFlags = 0; + + Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask| + StructureNotifyMask|FocusChangeMask, + ScrollbarEventProc, (ClientData) macScrollPtr); + + 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; +} + +/* + *-------------------------------------------------------------- + * + * TkpDisplayScrollbar -- + * + * This procedure redraws the contents of a scrollbar window. + * It is invoked as a do-when-idle handler, so it only runs + * when there's nothing else for the application to do. + * + * Results: + * None. + * + * Side effects: + * Information appears on the screen. + * + *-------------------------------------------------------------- + */ + +void +TkpDisplayScrollbar( + ClientData clientData) /* Information about window. */ +{ + TkScrollbar *scrollPtr = (TkScrollbar *) clientData; + MacScrollbar *macScrollPtr = (MacScrollbar *) clientData; + Tk_Window tkwin = scrollPtr->tkwin; + + MacDrawable *macDraw; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + WindowRef windowRef; + + if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + goto done; + } + + /* + * Draw the focus or any 3D relief we may have. + */ + if (scrollPtr->highlightWidth != 0) { + GC fgGC, bgGC; + + bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, + Tk_WindowId(tkwin)); + + if (scrollPtr->flags & GOT_FOCUS) { + fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, + Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, scrollPtr->highlightWidth, + Tk_WindowId(tkwin)); + } else { + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, scrollPtr->highlightWidth, + Tk_WindowId(tkwin)); + } + } + 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); + + /* + * Set up port for drawing Macintosh control. + */ + macDraw = (MacDrawable *) Tk_WindowId(tkwin); + destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin)); + + if (macScrollPtr->sbHandle == NULL) { + Rect r; + SInt16 initialValue; + SInt16 minValue; + SInt16 maxValue; + SInt16 procID; + WindowRef frontNonFloating; + + r.left = r.top = 0; + r.right = r.bottom = 1; + + minValue = MIN_SCROLLBAR_VALUE; + maxValue = MAX_SCROLLBAR_VALUE; + initialValue = (minValue + maxValue)/2; + procID = kControlScrollBarLiveProc; + + windowRef = GetWindowFromPort(destPort); + macScrollPtr->sbHandle = NewControl(windowRef, &r, "\p", + false, initialValue,minValue,maxValue, + procID, (SInt32) scrollPtr); + + /* + * If we are foremost then make us active. + */ + + frontNonFloating = FrontNonFloatingWindow(); + + if ((windowRef == FrontWindow()) || TkpIsWindowFloating(windowRef)) { + macScrollPtr->macFlags |= ACTIVE; + } + } + + /* + * Update the control values before we draw. + */ + windowRef = GetControlOwner (macScrollPtr->sbHandle); + UpdateControlValues(macScrollPtr); + + if (macScrollPtr->macFlags & ACTIVE) { + Draw1Control(macScrollPtr->sbHandle); + if (macScrollPtr->macFlags & DRAW_GROW) { + DrawGrowIcon(windowRef); + } + } else { + HiliteControl (macScrollPtr->sbHandle, 255 ); + Draw1Control(macScrollPtr->sbHandle); + if (macScrollPtr->macFlags & DRAW_GROW) { + DrawGrowIcon(windowRef); + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder, + Tk_Width(tkwin) - 13, Tk_Height(tkwin) - 13, + Tk_Width(tkwin), Tk_Height(tkwin), + 0, TK_RELIEF_FLAT); + } + } + + SetGWorld(saveWorld, saveDevice); + + 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. */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * TkpComputeScrollbarGeometry -- + * + * After changes in a scrollbar's size or configuration, this + * procedure recomputes various geometry information used in + * displaying the scrollbar. + * + * Results: + * None. + * + * Side effects: + * The scrollbar will be displayed differently. + * + *---------------------------------------------------------------------- + */ + +void +TkpComputeScrollbarGeometry( + register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may + * have changed. */ +{ + MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; + int width, fieldLength, adjust = 0; + + if (scrollPtr->highlightWidth < 0) { + scrollPtr->highlightWidth = 0; + } + scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; + width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin) + : Tk_Height(scrollPtr->tkwin); + scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1; + fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) + : Tk_Width(scrollPtr->tkwin)) + - 2*(scrollPtr->arrowLength + scrollPtr->inset); + if (fieldLength < 0) { + fieldLength = 0; + } + scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction; + 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). + */ + + if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) { + scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth; + } + if (scrollPtr->sliderFirst < 0) { + scrollPtr->sliderFirst = 0; + } + if (scrollPtr->sliderLast < (scrollPtr->sliderFirst + + MIN_SLIDER_LENGTH)) { + scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH; + } + if (scrollPtr->sliderLast > fieldLength) { + scrollPtr->sliderLast = fieldLength; + } + scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset; + scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset; + + /* + * 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) { + if ((macScrollPtr->macFlags & AUTO_ADJUST) && + (macScrollPtr->macFlags & (FLUSH_RIGHT|FLUSH_LEFT))) { + adjust--; + } + Tk_GeometryRequest(scrollPtr->tkwin, + scrollPtr->width + 2*scrollPtr->inset + adjust, + 2*(scrollPtr->arrowLength + scrollPtr->borderWidth + + scrollPtr->inset)); + } else { + if ((macScrollPtr->macFlags & AUTO_ADJUST) && + (macScrollPtr->macFlags & (FLUSH_TOP|FLUSH_BOTTOM))) { + adjust--; + } + Tk_GeometryRequest(scrollPtr->tkwin, + 2*(scrollPtr->arrowLength + scrollPtr->borderWidth + + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset + adjust); + } + Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyScrollbar -- + * + * Free data structures associated with the scrollbar control. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyScrollbar( + TkScrollbar *scrollPtr) /* Scrollbar to destroy. */ +{ + MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr; + + if (macScrollPtr->sbHandle != NULL) { + if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) { + DisposeControl(macScrollPtr->sbHandle); + macScrollPtr->sbHandle = NULL; + } + } + macScrollPtr->macFlags |= ALREADY_DEAD; +} + +/* + *-------------------------------------------------------------- + * + * TkpScrollbarPosition -- + * + * Determine the scrollbar element corresponding to a + * given position. + * + * Results: + * One of TOP_ARROW, TOP_GAP, etc., indicating which element + * of the scrollbar covers the position given by (x, y). If + * (x,y) is outside the scrollbar entirely, then OUTSIDE is + * returned. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkpScrollbarPosition( + TkScrollbar *scrollPtr, /* Scrollbar widget record. */ + int x, int y) /* Coordinates within scrollPtr's + * window. */ +{ + MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; + GWorldPtr destPort; + int length, width, tmp, inactive = false; + ControlPartCode part; + Point where; + Rect bounds; + int x0, y0; + + x0 = x; + y0 = y; + + if (scrollPtr->vertical) { + length = Tk_Height(scrollPtr->tkwin); + width = Tk_Width(scrollPtr->tkwin); + } else { + tmp = x; + x = y; + y = tmp; + length = Tk_Width(scrollPtr->tkwin); + width = Tk_Height(scrollPtr->tkwin); + } + + if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset)) + || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) { + return OUTSIDE; + } + + /* + * All of the calculations in this procedure mirror those in + * 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)); + SetGWorld(destPort, NULL); + UpdateControlValues(macScrollPtr); + if ( GetControlHilite(macScrollPtr->sbHandle) == 255 ) { + inactive = true; + HiliteControl(macScrollPtr->sbHandle, 0 ); + } + + TkMacOSXWinBounds((TkWindow *) scrollPtr->tkwin, &bounds); + where.h = x0 + bounds.left; + where.v = y0 + bounds.top; + part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where); + if (inactive) { + HiliteControl(macScrollPtr->sbHandle, 255 ); + } + switch (part) { + case kControlUpButtonPart: + return TOP_ARROW; + case kControlPageUpPart: + return TOP_GAP; + case kControlIndicatorPart: + return SLIDER; + case kControlPageDownPart: + return BOTTOM_GAP; + case kControlDownButtonPart: + return BOTTOM_ARROW; + default: + return OUTSIDE; + } +} + +/* + *-------------------------------------------------------------- + * + * ThumbActionProc -- + * + * Callback procedure used by the Macintosh toolbox call + * TrackControl. 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() +{ + register TkScrollbar *scrollPtr = activeScrollPtr; + register MacScrollbar *macScrollPtr = (MacScrollbar *) activeScrollPtr; + Tcl_DString cmdString; + int origValue, trackBarPin; + double thumbWidth, newFirstFraction, trackBarSize; + char valueString[40]; + Point currentPoint = { 0, 0 }; + Rect trackRect; + Tcl_Interp *interp; + MouseTrackingResult trackingResult; + OSErr err; + + if (scrollPtr == NULL) { + return; + } + + Tcl_DStringInit(&cmdString); + + /* + * First compute values that will remain constant during the tracking + * of the thumb. The variable trackBarSize is the length of the scrollbar + * minus the 2 arrows and half the width of the thumb on both sides + * (3 * arrowLength). The variable trackBarPin is the lower starting point + * of the drag region. + * + * Note: the arrowLength is equal to the thumb width of a Mac scrollbar. + */ + + origValue = GetControlValue(macScrollPtr->sbHandle); + GetControlBounds(macScrollPtr->sbHandle, &trackRect); + if (scrollPtr->vertical == true) { + trackBarSize = (double) (trackRect.bottom - trackRect.top + - (scrollPtr->arrowLength * 3)); + trackBarPin = trackRect.top + scrollPtr->arrowLength + + (scrollPtr->arrowLength / 2); + InsetRect(&trackRect, -25, -113); + + } else { + trackBarSize = (double) (trackRect.right - trackRect.left + - (scrollPtr->arrowLength * 3)); + trackBarPin = trackRect.left + scrollPtr->arrowLength + + (scrollPtr->arrowLength / 2); + 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. + */ + + do { + err = TrackMouseLocationWithOptions(NULL, + kTrackMouseLocationOptionDontConsumeMouseUp, + kEventDurationForever, + ¤tPoint, + NULL, + &trackingResult); + + if ((err==noErr) + && ((trackingResult == kMouseTrackingMouseDragged) + || (trackingResult == kMouseTrackingMouseMoved))) { + /* + * Calculating this value is a little tricky. We need to calculate a + * value for where the thumb would be in a Motif widget (variable + * thumb). This value is what the "command" expects and is what will + * be resent to the scrollbar to update its value. + */ + thumbWidth = scrollPtr->lastFraction - scrollPtr->firstFraction; + if (PtInRect(currentPoint, &trackRect)) { + if (scrollPtr->vertical == true) { + newFirstFraction = (1.0 - thumbWidth) * + ((double) (currentPoint.v - trackBarPin) / trackBarSize); + } else { + newFirstFraction = (1.0 - thumbWidth) * + ((double) (currentPoint.h - trackBarPin) / trackBarSize); + } + } else { + newFirstFraction = ((double) origValue / MAX_SCROLLBAR_DVALUE) + * (1.0 - thumbWidth); + } + 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_GlobalEval(interp, cmdString.string); + Tcl_Release((ClientData) interp); + Tcl_DStringSetLength(&cmdString, 0); + Tcl_DStringAppend(&cmdString, "update idletasks", + strlen("update idletasks")); + Tcl_Preserve((ClientData) interp); + Tcl_GlobalEval(interp, cmdString.string); + Tcl_Release((ClientData) interp); + } + } while ((err==noErr) && trackingResult!=kMouseTrackingMouseReleased ); + + Tcl_DStringFree(&cmdString); + return; +} + +/* + *-------------------------------------------------------------- + * + * ScrollbarActionProc -- + * + * Callback procedure used by the Macintosh toolbox call + * TrackControl. 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 *) GetControlReference(theControl); + Tcl_DString cmdString; + + Tcl_DStringInit(&cmdString); + Tcl_DStringAppend(&cmdString, scrollPtr->command, + scrollPtr->commandSize); + + if ( partCode == kControlUpButtonPart || + partCode == kControlDownButtonPart ) { + Tcl_DStringAppendElement(&cmdString, "scroll"); + Tcl_DStringAppendElement(&cmdString, + (partCode == kControlUpButtonPart ) ? "-1" : "1"); + Tcl_DStringAppendElement(&cmdString, "unit"); + } else if (partCode == kControlPageUpPart || partCode == kControlPageDownPart ) { + Tcl_DStringAppendElement(&cmdString, "scroll"); + Tcl_DStringAppendElement(&cmdString, + (partCode == kControlPageUpPart ) ? "-1" : "1"); + Tcl_DStringAppendElement(&cmdString, "page"); + } + Tcl_Preserve((ClientData) scrollPtr->interp); + Tcl_DStringAppend(&cmdString, "; update idletasks", + strlen("; update idletasks")); + Tcl_GlobalEval(scrollPtr->interp, cmdString.string); + Tcl_Release((ClientData) scrollPtr->interp); + + Tcl_DStringFree(&cmdString); +} + +/* + *-------------------------------------------------------------- + * + * 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; + int part, x, y, dummy; + unsigned int state; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + 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)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + 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); + if (part == kControlIndicatorPart && 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. + * Set the global activeScrollPtr to the current control + * so the callback may have access to it. + */ + activeScrollPtr = scrollPtr; + part = TrackControl(macScrollPtr->sbHandle, where, + (ControlActionUPP) thumbActionProc); + activeScrollPtr = NULL; + } else if (part == kControlIndicatorPart) { + /* + * Case 2: in thumb with jump scrolling. Call TrackControl + * with a NULL action proc. Use the new value of the control + * to set update the control. + */ + part = TrackControl(macScrollPtr->sbHandle, where, NULL); + if (part == kControlIndicatorPart) { + double newFirstFraction, thumbWidth; + Tcl_DString cmdString; + char valueString[TCL_DOUBLE_SPACE]; + + /* + * The following calculation takes the new control + * value and maps it to what Tk needs for its variable + * thumb size representation. + */ + thumbWidth = scrollPtr->lastFraction + - scrollPtr->firstFraction; + newFirstFraction = (1.0 - thumbWidth) * + ((double) GetControlValue(macScrollPtr->sbHandle) / MAX_SCROLLBAR_DVALUE); + sprintf(valueString, "%g", newFirstFraction); + + Tcl_DStringInit(&cmdString); + Tcl_DStringAppend(&cmdString, scrollPtr->command, + strlen(scrollPtr->command)); + Tcl_DStringAppendElement(&cmdString, "moveto"); + Tcl_DStringAppendElement(&cmdString, valueString); + Tcl_DStringAppend(&cmdString, "; update idletasks", + strlen("; update idletasks")); + + interp = scrollPtr->interp; + Tcl_Preserve((ClientData) interp); + Tcl_GlobalEval(interp, cmdString.string); + Tcl_Release((ClientData) interp); + Tcl_DStringFree(&cmdString); + } + } else if (part != 0) { + /* + * Case 3: in any other part of the scrollbar. We call + * TrackControl with the scrollActionProc which will do + * most all the work. + */ + TrackControl(macScrollPtr->sbHandle, where, scrollActionProc); + HiliteControl(macScrollPtr->sbHandle, 0); + } + + /* + * The TrackControl call will "eat" the ButtonUp event. We now + * generate a ButtonUp event so Tk will unset implicit grabs etc. + */ + GetMouse(&where); + XQueryPointer(NULL, None, &window, &window, &x, + &y, &dummy, &dummy, &state); + window = Tk_WindowId(scrollPtr->tkwin); + TkGenerateButtonEvent(x, y, window, state); + + SetGWorld(saveWorld, saveDevice); + } + + 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; +} + +/* + *-------------------------------------------------------------- + * + * ScrollbarEventProc -- + * + * 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. + * + *-------------------------------------------------------------- + */ + +static void +ScrollbarEventProc( + ClientData clientData, /* Information about window. */ + XEvent *eventPtr) /* Information about event. */ +{ + TkScrollbar *scrollPtr = (TkScrollbar *) clientData; + MacScrollbar *macScrollPtr = (MacScrollbar *) clientData; + + if (eventPtr->type == UnmapNotify) { + TkMacOSXSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false); + } else if (eventPtr->type == ActivateNotify) { + macScrollPtr->macFlags |= ACTIVE; + TkScrollbarEventuallyRedraw((ClientData) scrollPtr); + } else if (eventPtr->type == DeactivateNotify) { + macScrollPtr->macFlags &= ~ACTIVE; + TkScrollbarEventuallyRedraw((ClientData) scrollPtr); + } else { + 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. + * + *-------------------------------------------------------------- + */ + +static void +UpdateControlValues( + MacScrollbar *macScrollPtr) /* Scrollbar data struct. */ +{ + TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr; + Tk_Window tkwin = scrollPtr->tkwin; + MacDrawable * macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); + WindowRef windowRef = GetControlOwner(macScrollPtr->sbHandle); + double middle; + SInt32 viewSize; + int flushRight = false; + int flushBottom = false; + Rect contrlRect, portRect; + UInt8 contrlHilite; + + /* + * We can't use the Macintosh commands SizeControl and MoveControl as these + * calls will also cause a redraw which in our case will also cause + * flicker. To avoid this we adjust the control record directly. The + * Draw1Control command appears to just draw where ever the control says to + * draw so this seems right. + * + * NOTE: changing the control record directly may not work when + * Apple releases the Copland version of the MacOS (or when hell is cold). + */ + + 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; + + SetControlBounds(macScrollPtr->sbHandle, &contrlRect ); + + /* + * To make Tk applications look more like Macintosh applications without + * requiring additional work by the Tk developer we do some cute tricks. + * The first trick plays with the size of the widget to get it to overlap + * with the side of the window by one pixel (we don't do this if the placer + * is the geometry manager). The second trick shrinks the scrollbar if it + * it covers the area of the grow region ao the scrollbar can also draw + * the grow region if need be. + */ + if (!strcmp(macDraw->winPtr->geomMgrPtr->name, "place")) { + macScrollPtr->macFlags &= AUTO_ADJUST; + } else { + macScrollPtr->macFlags |= AUTO_ADJUST; + } + GetPortBounds ( GetWindowPort ( windowRef ), &portRect ); + if ( portRect.left == contrlRect.left ) { + if (macScrollPtr->macFlags & AUTO_ADJUST) { + contrlRect.left--; + SetControlBounds ( macScrollPtr->sbHandle, &contrlRect ); + } + if (!(macScrollPtr->macFlags & FLUSH_LEFT)) { + macScrollPtr->macFlags |= FLUSH_LEFT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_LEFT) { + macScrollPtr->macFlags &= ~FLUSH_LEFT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + if (portRect.top == contrlRect.top) { + if (macScrollPtr->macFlags & AUTO_ADJUST) { + contrlRect.top--; + } + if (!(macScrollPtr->macFlags & FLUSH_TOP)) { + macScrollPtr->macFlags |= FLUSH_TOP; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_TOP) { + macScrollPtr->macFlags &= ~FLUSH_TOP; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + if (portRect.right == contrlRect.right) { + flushRight = true; + if (macScrollPtr->macFlags & AUTO_ADJUST) { + contrlRect.right++; + } + if (!(macScrollPtr->macFlags & FLUSH_RIGHT)) { + macScrollPtr->macFlags |= FLUSH_RIGHT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_RIGHT) { + macScrollPtr->macFlags &= ~FLUSH_RIGHT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + if (portRect.bottom == contrlRect.bottom) { + flushBottom = true; + if (macScrollPtr->macFlags & AUTO_ADJUST) { + contrlRect.bottom++; + } + if (!(macScrollPtr->macFlags & FLUSH_BOTTOM)) { + macScrollPtr->macFlags |= FLUSH_BOTTOM; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_BOTTOM) { + macScrollPtr->macFlags &= ~FLUSH_BOTTOM; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + /* + * If the scrollbar is flush against the bottom right hand corner then + * it may need to draw the grow region for the window so we let the + * wm code know about this scrollbar. We don't actually draw the grow + * region, however, unless we are currently resizable. + */ + macScrollPtr->macFlags &= ~DRAW_GROW; + if (flushBottom && flushRight) { + TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, true); + if (TkMacOSXResizable(macDraw->toplevel->winPtr)) { + if (scrollPtr->vertical) { + contrlRect.bottom -= 14; + } else { + contrlRect.right -= 14; + } + macScrollPtr->macFlags |= DRAW_GROW; + } + } else { + TkMacOSXSetScrollbarGrow((TkWindow *) tkwin, false); + } + + /* + * Given the Tk parameters for the fractions of the start and + * end of the thumb, the following calculation determines the + * location for the fixed sized Macintosh thumb. + */ + middle = scrollPtr->firstFraction / (scrollPtr->firstFraction + + (1.0 - scrollPtr->lastFraction)); + viewSize = (SInt32)((scrollPtr->lastFraction-scrollPtr->firstFraction) + * MAX_SCROLLBAR_DVALUE); + SetControlViewSize(macScrollPtr->sbHandle,viewSize); + SetControlValue(macScrollPtr->sbHandle, + (short) (middle * MAX_SCROLLBAR_VALUE) ); + contrlHilite=GetControlHilite(macScrollPtr->sbHandle); + if ( contrlHilite == 0 || contrlHilite == 255) { + if (scrollPtr->firstFraction == 0.0 && + scrollPtr->lastFraction == 1.0) { + HiliteControl(macScrollPtr->sbHandle,255); + } else { + HiliteControl(macScrollPtr->sbHandle,0); + } + } + if ( !IsControlVisible (macScrollPtr -> sbHandle) ) { + SetControlVisibility(macScrollPtr->sbHandle,TRUE,FALSE); + } +} |