diff options
author | das <das@noemail.net> | 2002-08-31 06:12:19 (GMT) |
---|---|---|
committer | das <das@noemail.net> | 2002-08-31 06:12:19 (GMT) |
commit | 648ac3876ec59c37e19a196edb935c3e80c39213 (patch) | |
tree | 303845583d22d9e5e5f3f53edf451167cb5847e6 /macosx/tkMacOSXDraw.c | |
parent | 7e140d6c071ee633bf9cd1b45efc08252bb26974 (diff) | |
download | tk-648ac3876ec59c37e19a196edb935c3e80c39213.zip tk-648ac3876ec59c37e19a196edb935c3e80c39213.tar.gz tk-648ac3876ec59c37e19a196edb935c3e80c39213.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
FossilOrigin-Name: 6b4c1410c56a191e66a5d9fdeed5b10c8b44eaa0
Diffstat (limited to 'macosx/tkMacOSXDraw.c')
-rw-r--r-- | macosx/tkMacOSXDraw.c | 1714 |
1 files changed, 1714 insertions, 0 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c new file mode 100644 index 0000000..3edcfe9 --- /dev/null +++ b/macosx/tkMacOSXDraw.c @@ -0,0 +1,1714 @@ +/* + * tkMacOSXDraw.c -- + * + * This file contains functions that perform drawing to + * Xlib windows. Most of the functions simple emulate + * Xlib functions. + * + * Copyright (c) 1995-1997 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: tkMacOSXDraw.c,v 1.2 2002/08/31 06:12:29 das Exp $ + */ + +#include "tkInt.h" +#include "X11/X.h" +#include "X11/Xlib.h" +#include <stdio.h> + +#include <Carbon/Carbon.h> +#include "tkMacOSXInt.h" +#include "tkPort.h" +#include "tkMacOSXDebug.h" + +#ifndef PI +# define PI 3.14159265358979323846 +#endif +#define RGBFLOATRED( c ) (float)((float)(c.red) / 65535.0) +#define RGBFLOATGREEN( c ) (float)((float)(c.green) / 65535.0) +#define RGBFLOATBLUE( c ) (float)((float)(c.blue) / 65535.0) + +/* + * Temporary regions that can be reused. + */ + +static RgnHandle tmpRgn = NULL; +static RgnHandle tmpRgn2 = NULL; + +static PixPatHandle gPenPat = NULL; + +static int useCGDrawing = 0; + +/* + * Prototypes for functions used only in this file. + */ +static unsigned char InvertByte _ANSI_ARGS_((unsigned char data)); + +void TkMacOSXSetUpCGContext(MacDrawable *macWin, + CGrafPtr destPort, GC gc, CGContextRef *contextPtr); +void TkMacOSXReleaseCGContext(MacDrawable *macWin, CGrafPtr destPort, + CGContextRef *context); +/* + *---------------------------------------------------------------------- + * + * XCopyArea -- + * + * Copies data from one drawable to another using block transfer + * routines. + * + * Results: + * None. + * + * Side effects: + * Data is moved from a window or bitmap to a second window or + * bitmap. + * + *---------------------------------------------------------------------- + */ + +void +XCopyArea( + Display* display, /* Display. */ + Drawable src, /* Source drawable. */ + Drawable dst, /* Destination drawable. */ + GC gc, /* GC to use. */ + int src_x, /* X & Y, width & height */ + int src_y, /* define the source rectangle */ + unsigned int width, /* the will be copied. */ + unsigned int height, + int dest_x, /* Dest X & Y on dest rect. */ + int dest_y) +{ + Rect srcRect, dstRect; + Rect * srcPtr, * dstPtr; + const BitMap * srcBit; + const BitMap * dstBit; + MacDrawable *srcDraw = (MacDrawable *) src; + MacDrawable *dstDraw = (MacDrawable *) dst; + CGrafPtr srcPort, dstPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + short tmode; + RGBColor origForeColor, origBackColor, whiteColor, blackColor; + Rect clpRect; + + dstPort = TkMacOSXGetDrawablePort(dst); + srcPort = TkMacOSXGetDrawablePort(src); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(dstPort, NULL); + GetForeColor(&origForeColor); + GetBackColor(&origBackColor); + whiteColor.red = 0; + whiteColor.blue = 0; + whiteColor.green = 0; + RGBForeColor(&whiteColor); + blackColor.red = 0xFFFF; + blackColor.blue = 0xFFFF; + blackColor.green = 0xFFFF; + RGBBackColor(&blackColor); + + if (tmpRgn2 == NULL) { + tmpRgn2 = NewRgn(); + } + srcPtr = &srcRect; + SetRect(&srcRect, (short) (srcDraw->xOff + src_x), + (short) (srcDraw->yOff + src_y), + (short) (srcDraw->xOff + src_x + width ), + (short) (srcDraw->yOff + src_y + height)); + if (tkPictureIsOpen ) { + dstPtr = &srcRect; + } else { + dstPtr = &dstRect; + SetRect(&dstRect, (short) (dstDraw->xOff + dest_x), + (short) (dstDraw->yOff + dest_y), + (short) (dstDraw->xOff + dest_x + width ), + (short) (dstDraw->yOff + dest_y + height)); + } + TkMacOSXSetUpClippingRgn(dst); + /* + * We will change the clip rgn in this routine, so we need to + * be able to restore it when we exit. + */ + + GetClip(tmpRgn2); + if (tkPictureIsOpen) { + /* + * When rendering into a picture, after a call to "OpenCPicture" + * the clipping is seriously WRONG and also INCONSISTENT with the + * clipping for single plane bitmaps. + * To circumvent this problem, we clip to the whole window + * In this case, would have also clipped to the srcRect + * ClipRect(&srcRect); + */ + GetPortBounds(dstPort,&clpRect); + dstPtr = &srcRect; + ClipRect(&clpRect); + } + if (!gc->clip_mask ) { + } else if (((TkpClipMask*)gc->clip_mask)->type == TKP_CLIP_REGION) { + RgnHandle clipRgn = (RgnHandle) + ((TkpClipMask*)gc->clip_mask)->value.region; + + int xOffset, yOffset; + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + if (!tkPictureIsOpen) { + xOffset = dstDraw->xOff + gc->clip_x_origin; + yOffset = dstDraw->yOff + gc->clip_y_origin; + OffsetRgn(clipRgn, xOffset, yOffset); + } + GetClip(tmpRgn); + SectRgn(tmpRgn, clipRgn, tmpRgn); + SetClip(tmpRgn); + if (!tkPictureIsOpen) { + OffsetRgn(clipRgn, -xOffset, -yOffset); + } + } + srcBit = GetPortBitMapForCopyBits( srcPort ); + dstBit = GetPortBitMapForCopyBits( dstPort ); + tmode = srcCopy; + + CopyBits(srcBit, dstBit, srcPtr, dstPtr, tmode, NULL); + RGBForeColor(&origForeColor); + RGBBackColor(&origBackColor); + SetClip(tmpRgn2); + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XCopyPlane -- + * + * Copies a bitmap from a source drawable to a destination + * drawable. The plane argument specifies which bit plane of + * the source contains the bitmap. Note that this implementation + * ignores the gc->function. + * + * Results: + * None. + * + * Side effects: + * Changes the destination drawable. + * + *---------------------------------------------------------------------- + */ + +void +XCopyPlane( + Display* display, /* Display. */ + Drawable src, /* Source drawable. */ + Drawable dst, /* Destination drawable. */ + GC gc, /* The GC to use. */ + int src_x, /* X, Y, width & height */ + int src_y, /* define the source rect. */ + unsigned int width, + unsigned int height, + int dest_x, /* X & Y on dest where we will copy. */ + int dest_y, + unsigned long plane) /* Which plane to copy. */ +{ + Rect srcRect, dstRect; + Rect * srcPtr, * dstPtr; + const BitMap * srcBit; + const BitMap * dstBit; + const BitMap * mskBit; + MacDrawable *srcDraw = (MacDrawable *) src; + MacDrawable *dstDraw = (MacDrawable *) dst; + GWorldPtr srcPort, dstPort, mskPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + RGBColor macColor; + TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask; + short tmode; + + srcPort = TkMacOSXGetDrawablePort(src); + dstPort = TkMacOSXGetDrawablePort(dst); + + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(dstPort, NULL); + + TkMacOSXSetUpClippingRgn(dst); + + + srcBit = GetPortBitMapForCopyBits ( srcPort ); + dstBit = GetPortBitMapForCopyBits ( dstPort ); + SetRect(&srcRect, (short) (srcDraw->xOff + src_x), + (short) (srcDraw->yOff + src_y), + (short) (srcDraw->xOff + src_x + width), + (short) (srcDraw->yOff + src_y + height)); + srcPtr = &srcRect; + if (tkPictureIsOpen) { + /* + * When rendering into a picture, after a call to "OpenCPicture" + * the clipping is seriously WRONG and also INCONSISTENT with the + * clipping for color bitmaps. + * To circumvent this problem, we clip to the whole window + */ + Rect clpRect; + GetPortBounds(dstPort,&clpRect); + ClipRect(&clpRect); + dstPtr = &srcRect; + } else { + dstPtr = &dstRect; + SetRect(&dstRect, (short) (dstDraw->xOff + dest_x), + (short) (dstDraw->yOff + dest_y), + (short) (dstDraw->xOff + dest_x + width), + (short) (dstDraw->yOff + dest_y + height)); + } + tmode = srcOr; + tmode = srcCopy + transparent; + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + RGBForeColor(&macColor); + } + + if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) { + + /* + * Case 1: opaque bitmaps. + */ + TkSetMacColor(gc->background, &macColor); + RGBBackColor(&macColor); + tmode = srcCopy; + CopyBits(srcBit, dstBit, srcPtr, dstPtr, tmode, NULL); + } else if (clipPtr->type == TKP_CLIP_PIXMAP) { + if (clipPtr->value.pixmap == src) { + PixMapHandle pm; + /* + * Case 2: transparent bitmaps. If it's color we ignore + * the forecolor. + */ + pm=GetPortPixMap(srcPort); + if (GetPixDepth(pm)== 1) { + tmode = srcOr; + } else { + tmode = transparent; + } + CopyBits(srcBit, dstBit, srcPtr, dstPtr, tmode, NULL); + } else { + /* + * Case 3: two arbitrary bitmaps. + */ + tmode = srcCopy; + mskPort = TkMacOSXGetDrawablePort(clipPtr->value.pixmap); + mskBit = GetPortBitMapForCopyBits ( mskPort ); + CopyDeepMask(srcBit, mskBit, dstBit, + srcPtr, srcPtr, dstPtr, tmode, NULL); + } + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * TkPutImage -- + * + * Copies a subimage from an in-memory image to a rectangle of + * of the specified drawable. + * + * Results: + * None. + * + * Side effects: + * Draws the image on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +TkPutImage( + unsigned long *colors, /* Unused on Macintosh. */ + int ncolors, /* Unused on Macintosh. */ + Display* display, /* Display. */ + Drawable d, /* Drawable to place image on. */ + GC gc, /* GC to use. */ + XImage* image, /* Image to place. */ + int src_x, /* Source X & Y. */ + int src_y, + int dest_x, /* Destination X & Y. */ + int dest_y, + unsigned int width, /* Same width & height for both */ + unsigned int height) /* distination and source. */ +{ + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + const BitMap * destBits; + int i, j; + BitMap bitmap; + char *newData = NULL; + Rect destRect, srcRect; + + destPort = TkMacOSXGetDrawablePort(d); + SetRect(&destRect, dest_x, dest_y, dest_x + width, dest_y + height); + SetRect(&srcRect, src_x, src_y, src_x + width, src_y + height); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + if (image->depth == 1) { + + /* + * This code assumes a pixel depth of 1 + */ + + bitmap.bounds.top = bitmap.bounds.left = 0; + bitmap.bounds.right = (short) image->width; + bitmap.bounds.bottom = (short) image->height; + if ((image->bytes_per_line % 2) == 1) { + char *newPtr, *oldPtr; + newData = (char *) ckalloc(image->height * + (image->bytes_per_line + 1)); + newPtr = newData; + oldPtr = image->data; + for (i = 0; i < image->height; i++) { + for (j = 0; j < image->bytes_per_line; j++) { + *newPtr = InvertByte((unsigned char) *oldPtr); + newPtr++, oldPtr++; + } + *newPtr = 0; + newPtr++; + } + bitmap.baseAddr = newData; + bitmap.rowBytes = image->bytes_per_line + 1; + } else { + newData = (char *) ckalloc(image->height * image->bytes_per_line); + for (i = 0; i < image->height * image->bytes_per_line; i++) { + newData[i] = InvertByte((unsigned char) image->data[i]); + } + bitmap.baseAddr = newData; + bitmap.rowBytes = image->bytes_per_line; + } + destBits = GetPortBitMapForCopyBits ( destPort ); + CopyBits(&bitmap, destBits, + &srcRect, &destRect, srcCopy, NULL); + + } else { + /* Color image */ + PixMap pixmap; + + pixmap.bounds.left = 0; + pixmap.bounds.top = 0; + pixmap.bounds.right = (short) image->width; + pixmap.bounds.bottom = (short) image->height; + pixmap.pixelType = RGBDirect; + pixmap.pmVersion = 4; /* 32bit clean */ + pixmap.packType = 0; + pixmap.packSize = 0; + pixmap.hRes = 0x00480000; + pixmap.vRes = 0x00480000; + pixmap.pixelSize = 32; + pixmap.cmpCount = 3; + pixmap.cmpSize = 8; + pixmap.pixelFormat = 0; + pixmap.pmTable = NULL; + pixmap.pmExt = 0; + pixmap.baseAddr = image->data; + pixmap.rowBytes = image->bytes_per_line | 0x8000; + + CopyBits((BitMap *) &pixmap, GetPortBitMapForCopyBits ( destPort ), + &srcRect, &destRect, srcCopy, NULL); + } + + if (newData != NULL) { + ckfree(newData); + } + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillRectangles -- + * + * Fill multiple rectangular areas in the given drawable. + * + * Results: + * None. + * + * Side effects: + * Draws onto the specified drawable. + * + *---------------------------------------------------------------------- + */ +void +XFillRectangles( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + XRectangle *rectangles, /* Rectangle array. */ + int n_rectangels) /* Number of rectangles. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Rect theRect; + int i; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + TkMacOSXSetUpGraphicsPort(gc, destPort); + + for (i=0; i<n_rectangels; i++) { + theRect.left = (short) (macWin->xOff + rectangles[i].x); + theRect.top = (short) (macWin->yOff + rectangles[i].y); + theRect.right = (short) (theRect.left + rectangles[i].width); + theRect.bottom = (short) (theRect.top + rectangles[i].height); + FillCRect(&theRect, gPenPat); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawLines -- + * + * Draw connected lines. + * + * Results: + * None. + * + * Side effects: + * Renders a series of connected lines. + * + *---------------------------------------------------------------------- + */ + +void +XDrawLines( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + XPoint* points, /* Array of points. */ + int npoints, /* Number of points. */ + int mode) /* Line drawing mode. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + CGrafPtr saveWorld; + GWorldPtr destPort; + GDHandle saveDevice; + int i; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + if (npoints < 2) { + return; /* TODO: generate BadValue error. */ + } + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + if (useCGDrawing) { + CGContextRef outContext; + + TkMacOSXSetUpCGContext(macWin, destPort, gc, &outContext); + + CGContextBeginPath(outContext); + CGContextMoveToPoint(outContext, (float) points[0].x, + (float) points[0].y); + if (mode == CoordModeOrigin) { + for (i = 1; i < npoints; i++) { + CGContextAddLineToPoint(outContext, + (float) points[i].x, + (float) points[i].y); + } + } + + CGContextStrokePath(outContext); + TkMacOSXReleaseCGContext(macWin, destPort, &outContext); + } else { + TkMacOSXSetUpGraphicsPort(gc, destPort); + + ShowPen(); + + PenPixPat(gPenPat); + MoveTo((short) (macWin->xOff + points[0].x), + (short) (macWin->yOff + points[0].y)); + for (i = 1; i < npoints; i++) { + if (mode == CoordModeOrigin) { + LineTo((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } else { + Line((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } + } + HidePen(); + + } + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawSegments -- + * + * Draw unconnected lines. + * + * Results: + * None. + * + * Side effects: + * Renders a series of connected lines. + * + *---------------------------------------------------------------------- + */ + +void XDrawSegments( + Display *display, + Drawable d, + GC gc, + XSegment *segments, + int nsegments) +{ + MacDrawable *macWin = (MacDrawable *) d; + CGrafPtr saveWorld; + GWorldPtr destPort; + GDHandle saveDevice; + int i; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + if (useCGDrawing) { + CGContextRef outContext; + + TkMacOSXSetUpCGContext(macWin, destPort, gc, &outContext); + + CGContextBeginPath(outContext); + for (i = 0; i < nsegments; i++) { + CGContextMoveToPoint(outContext, + (float) segments[i].x1, + (float) segments[i].y1); + CGContextAddLineToPoint (outContext, + (float) segments[i].x2, + (float) segments[i].y2); + } + CGContextStrokePath(outContext); + TkMacOSXReleaseCGContext(macWin, destPort, &outContext); + } else { + TkMacOSXSetUpGraphicsPort(gc, destPort); + + ShowPen(); + + PenPixPat(gPenPat); + for (i = 0; i < nsegments; i++) { + MoveTo((short) (macWin->xOff + segments[i].x1), + (short) (macWin->yOff + segments[i].y1)); + LineTo((short) (macWin->xOff + segments[i].x2), + (short) (macWin->yOff + segments[i].y2)); + } + HidePen(); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillPolygon -- + * + * Draws a filled polygon. + * + * Results: + * None. + * + * Side effects: + * Draws a filled polygon on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XFillPolygon( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + XPoint* points, /* Array of points. */ + int npoints, /* Number of points. */ + int shape, /* Shape to draw. */ + int mode) /* Drawing mode. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + PolyHandle polygon; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + int i; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + if (useCGDrawing) { + CGContextRef outContext; + + TkMacOSXSetUpCGContext(macWin, destPort, gc, &outContext); + + CGContextBeginPath(outContext); + CGContextMoveToPoint(outContext, (float) (points[0].x), + (float) (points[0].y)); + for (i = 1; i < npoints; i++) { + + if (mode == CoordModePrevious) { + CGContextAddLineToPoint(outContext, (float) points[i].x, + (float) points[i].y); + } else { + } + } + //CGContextStrokePath(outContext); + CGContextFillPath(outContext); + TkMacOSXReleaseCGContext(macWin, destPort, &outContext); + } else { + TkMacOSXSetUpGraphicsPort(gc, destPort); + + PenNormal(); + polygon = OpenPoly(); + + MoveTo((short) (macWin->xOff + points[0].x), + (short) (macWin->yOff + points[0].y)); + for (i = 1; i < npoints; i++) { + if (mode == CoordModePrevious) { + Line((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } else { + LineTo((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } + } + + ClosePoly(); + + FillCPoly(polygon, gPenPat); + + KillPoly(polygon); + } + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawRectangle -- + * + * Draws a rectangle. + * + * Results: + * None. + * + * Side effects: + * Draws a rectangle on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XDrawRectangle( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + int x, /* Upper left corner. */ + int y, + unsigned int width, /* Width & height of rect. */ + unsigned int height) +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect theRect; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + TkMacOSXSetUpGraphicsPort(gc, destPort); + + theRect.left = (short) (macWin->xOff + x); + theRect.top = (short) (macWin->yOff + y); + theRect.right = (short) (theRect.left + width); + theRect.bottom = (short) (theRect.top + height); + + ShowPen(); + PenPixPat(gPenPat); + FrameRect(&theRect); + HidePen(); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawRectangles -- + * + * Draws the outlines of the specified rectangles as if a + * five-point PolyLine protocol request were specified for each + * rectangle: + * + * [x,y] [x+width,y] [x+width,y+height] [x,y+height] + * [x,y] + * + * For the specified rectangles, these functions do not draw a + * pixel more than once. XDrawRectangles draws the rectangles in + * the order listed in the array. If rectangles intersect, the + * intersecting pixels are drawn multiple times. Draws a + * rectangle. + * + * Results: + * None. + * + * Side effects: + * Draws rectangles on the specified drawable. + * + *---------------------------------------------------------------------- + */ +void +XDrawRectangles( + Display *display, + Drawable drawable, + GC gc, + XRectangle *rectArr, + int nRects) +{ + MacDrawable *macWin = (MacDrawable *) drawable; + Rect rect; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + XRectangle * rectPtr; + int i; + + destPort = TkMacOSXGetDrawablePort(drawable); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(drawable); + + TkMacOSXSetUpGraphicsPort(gc, destPort); + + + ShowPen(); + PenPixPat(gPenPat); + + for (i = 0, rectPtr = rectArr; i < nRects;i++, rectPtr++ ) { + rect.left = (short) (macWin->xOff + rectPtr->x); + rect.top = (short) (macWin->yOff + rectPtr->y); + rect.right = (short) (rect.left + rectPtr->width); + rect.bottom = (short) (rect.top + rectPtr->height); + FrameRect(&rect); + } + HidePen(); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawArc -- + * + * Draw an arc. + * + * Results: + * None. + * + * Side effects: + * Draws an arc on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XDrawArc( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + int x, /* Upper left of */ + int y, /* bounding rect. */ + unsigned int width, /* Width & height. */ + unsigned int height, + int angle1, /* Staring angle of arc. */ + int angle2) /* Ending angle of arc. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect theRect; + short start, extent; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + float fX = (float) x, + fY = (float) y, + fWidth = (float) width, + fHeight = (float) height; + + if (width == 0 || height == 0) { + return; + } + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + if (useCGDrawing) { + CGContextRef outContext; + CGAffineTransform transform; + int clockwise = angle1 ? 0 : 1; + + TkMacOSXSetUpCGContext(macWin, destPort, gc, &outContext); + + CGContextBeginPath(outContext); + + /* + * If we are drawing an oval, we have to squash the coordinate + * system before drawing, since CGContextAddArcToPoint only draws + * circles. + */ + + CGContextSaveGState(outContext); + transform = CGAffineTransformMakeTranslation((float) (x + width/2), + (float) (y + height/2)); + transform = CGAffineTransformScale(transform, 1.0, fHeight/fWidth); + CGContextConcatCTM(outContext, transform); + + CGContextAddArc(outContext, 0.0, 0.0, + (float) width/2, + (float) angle1, (float) angle2, clockwise); + + CGContextRestoreGState(outContext); + + CGContextStrokePath(outContext); + TkMacOSXReleaseCGContext(macWin, destPort, &outContext); + } else { + TkMacOSXSetUpGraphicsPort(gc, destPort); + + + theRect.left = (short) (macWin->xOff + x); + theRect.top = (short) (macWin->yOff + y); + theRect.right = (short) (theRect.left + width); + theRect.bottom = (short) (theRect.top + height); + start = (short) (90 - (angle1 / 64)); + extent = (short) (-(angle2 / 64)); + + ShowPen(); + PenPixPat(gPenPat); + FrameArc(&theRect, start, extent); + HidePen(); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawArcs -- + * + * Draws multiple circular or elliptical arcs. Each arc is + * specified by a rectangle and two angles. The center of the + * circle or ellipse is the center of the rect- angle, and the + * major and minor axes are specified by the width and height. + * Positive angles indicate counterclock- wise motion, and + * negative angles indicate clockwise motion. If the magnitude + * of angle2 is greater than 360 degrees, XDrawArcs truncates it + * to 360 degrees. + * + * Results: + * None. + * + * Side effects: + * Draws an arc for each array element on the specified drawable. + * + *---------------------------------------------------------------------- + */ +void +XDrawArcs( + Display *display, + Drawable d, + GC gc, + XArc *arcArr, + int nArcs) +{ + + MacDrawable *macWin = (MacDrawable *) d; + Rect rect; + short start, extent; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + XArc * arcPtr; + int i; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + TkMacOSXSetUpGraphicsPort(gc, destPort); + + + ShowPen(); + PenPixPat(gPenPat); + for (i = 0, arcPtr = arcArr;i < nArcs;i++, arcPtr++ ) { + rect.left = (short) (macWin->xOff + arcPtr->x); + rect.top = (short) (macWin->yOff + arcPtr->y); + rect.right = (short) (rect.left + arcPtr->width); + rect.bottom = (short) (rect.top + arcPtr->height); + start = (short) (90 - (arcPtr->angle1 / 64)); + extent = (short) (-(arcPtr->angle2 / 64)); + FrameArc(&rect, start, extent); + } + HidePen(); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillArc -- + * + * Draw a filled arc. + * + * Results: + * None. + * + * Side effects: + * Draws a filled arc on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XFillArc( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + int x, /* Upper left of */ + int y, /* bounding rect. */ + unsigned int width, /* Width & height. */ + unsigned int height, + int angle1, /* Staring angle of arc. */ + int angle2) /* Ending angle of arc. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect theRect; + short start, extent; + PolyHandle polygon; + double sin1, cos1, sin2, cos2, angle; + double boxWidth, boxHeight; + double vertex[2], center1[2], center2[2]; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + TkMacOSXSetUpGraphicsPort(gc, destPort); + + theRect.left = (short) (macWin->xOff + x); + theRect.top = (short) (macWin->yOff + y); + theRect.right = (short) (theRect.left + width); + theRect.bottom = (short) (theRect.top + height); + start = (short) (90 - (angle1 / 64)); + extent = (short) (- (angle2 / 64)); + + if (gc->arc_mode == ArcChord) { + boxWidth = theRect.right - theRect.left; + boxHeight = theRect.bottom - theRect.top; + angle = -(angle1/64.0)*PI/180.0; + sin1 = sin(angle); + cos1 = cos(angle); + angle -= (angle2/64.0)*PI/180.0; + sin2 = sin(angle); + cos2 = cos(angle); + vertex[0] = (theRect.left + theRect.right)/2.0; + vertex[1] = (theRect.top + theRect.bottom)/2.0; + center1[0] = vertex[0] + cos1*boxWidth/2.0; + center1[1] = vertex[1] + sin1*boxHeight/2.0; + center2[0] = vertex[0] + cos2*boxWidth/2.0; + center2[1] = vertex[1] + sin2*boxHeight/2.0; + + polygon = OpenPoly(); + MoveTo((short) ((theRect.left + theRect.right)/2), + (short) ((theRect.top + theRect.bottom)/2)); + + LineTo((short) (center1[0] + 0.5), (short) (center1[1] + 0.5)); + LineTo((short) (center2[0] + 0.5), (short) (center2[1] + 0.5)); + ClosePoly(); + + ShowPen(); + FillCArc(&theRect, start, extent, gPenPat); + FillCPoly(polygon, gPenPat); + HidePen(); + + KillPoly(polygon); + } else { + ShowPen(); + FillCArc(&theRect, start, extent, gPenPat); + HidePen(); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillArcs -- + * + * Draw a filled arc. + * + * Results: + * None. + * + * Side effects: + * Draws a filled arc for each array element on the specified drawable. + * + *---------------------------------------------------------------------- + */ +void +XFillArcs( + Display *display, + Drawable d, + GC gc, + XArc *arcArr, + int nArcs) +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect rect; + short start, extent; + PolyHandle polygon; + double sin1, cos1, sin2, cos2, angle; + double boxWidth, boxHeight; + double vertex[2], center1[2], center2[2]; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + int i; + XArc * arcPtr; + + destPort = TkMacOSXGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(d); + + TkMacOSXSetUpGraphicsPort(gc, destPort); + + for (i = 0, arcPtr = arcArr;i<nArcs;i++, arcPtr++ ) { + rect.left = (short) (macWin->xOff + arcPtr->x); + rect.top = (short) (macWin->yOff + arcPtr->y); + rect.right = (short) (rect.left + arcPtr->width); + rect.bottom = (short) (rect.top + arcPtr->height); + start = (short) (90 - (arcPtr->angle1 / 64)); + extent = (short) (- (arcPtr->angle2 / 64)); + + if (gc->arc_mode == ArcChord) { + boxWidth = rect.right - rect.left; + boxHeight = rect.bottom - rect.top; + angle = -(arcPtr->angle1/64.0)*PI/180.0; + sin1 = sin(angle); + cos1 = cos(angle); + angle -= (arcPtr->angle2/64.0)*PI/180.0; + sin2 = sin(angle); + cos2 = cos(angle); + vertex[0] = (rect.left + rect.right)/2.0; + vertex[1] = (rect.top + rect.bottom)/2.0; + center1[0] = vertex[0] + cos1*boxWidth/2.0; + center1[1] = vertex[1] + sin1*boxHeight/2.0; + center2[0] = vertex[0] + cos2*boxWidth/2.0; + center2[1] = vertex[1] + sin2*boxHeight/2.0; + + polygon = OpenPoly(); + MoveTo((short) ((rect.left + rect.right)/2), + (short) ((rect.top + rect.bottom)/2)); + + LineTo((short) (center1[0] + 0.5), (short) (center1[1] + 0.5)); + LineTo((short) (center2[0] + 0.5), (short) (center2[1] + 0.5)); + ClosePoly(); + + ShowPen(); + FillCArc(&rect, start, extent, gPenPat); + FillCPoly(polygon, gPenPat); + HidePen(); + + KillPoly(polygon); + } else { + ShowPen(); + FillCArc(&rect, start, extent, gPenPat); + HidePen(); + } + } + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XMaxRequestSize -- + * + *---------------------------------------------------------------------- + */ +long +XMaxRequestSize(Display *display) +{ + return (SHRT_MAX / 4); +} + +/* + *---------------------------------------------------------------------- + * + * TkScrollWindow -- + * + * Scroll a rectangle of the specified window and accumulate + * a damage region. + * + * Results: + * Returns 0 if the scroll genereated no additional damage. + * Otherwise, sets the region that needs to be repainted after + * scrolling and returns 1. + * + * Side effects: + * Scrolls the bits in the window. + * + *---------------------------------------------------------------------- + */ + +int +TkScrollWindow( + Tk_Window tkwin, /* The window to be scrolled. */ + GC gc, /* GC for window to be scrolled. */ + int x, /* Position rectangle to be scrolled. */ + int y, + int width, + int height, + int dx, /* Distance rectangle should be moved. */ + int dy, + TkRegion damageRgn) /* Region to accumulate damage in. */ +{ + MacDrawable *destDraw = (MacDrawable *) Tk_WindowId(tkwin); + RgnHandle rgn = (RgnHandle) damageRgn; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Rect srcRect, scrollRect; + RgnHandle visRgn, clipRgn; + + destPort = TkMacOSXGetDrawablePort(Tk_WindowId(tkwin)); + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacOSXSetUpClippingRgn(Tk_WindowId(tkwin)); + + /* + * Due to the implementation below the behavior may be differnt + * than X in certain cases that should never occur in Tk. The + * scrollRect is the source rect extended by the offset (the union + * of the source rect and the offset rect). Everything + * in the extended scrollRect is scrolled. On X, it's possible + * to "skip" over an area if the offset makes the source and + * destination rects disjoint and non-aligned. + */ + + SetRect(&srcRect, (short) (destDraw->xOff + x), + (short) (destDraw->yOff + y), + (short) (destDraw->xOff + x + width), + (short) (destDraw->yOff + y + height)); + scrollRect = srcRect; + if (dx < 0) { + scrollRect.left += dx; + } else { + scrollRect.right += dx; + } + if (dy < 0) { + scrollRect.top += dy; + } else { + scrollRect.bottom += dy; + } + + /* + * Adjust clip region so that we don't copy any windows + * that may overlap us. + */ + visRgn = NewRgn(); + clipRgn = NewRgn(); + RectRgn(rgn, &srcRect); + GetPortVisibleRegion(destPort,visRgn); + DiffRgn(rgn, visRgn, rgn); + OffsetRgn(rgn, dx, dy); + GetPortClipRegion(destPort, clipRgn); + DiffRgn(clipRgn, rgn, clipRgn); + SetPortClipRegion(destPort, clipRgn); + SetEmptyRgn(rgn); + + /* + * When a menu is up, the Mac does not expect drawing to occur and + * does not clip out the menu. We have to do it ourselves. This + * is pretty gross. + */ + + if (tkUseMenuCascadeRgn == 1) { + Point scratch = {0, 0}; + MacDrawable *macDraw = (MacDrawable *) Tk_WindowId(tkwin); + + LocalToGlobal(&scratch); + CopyRgn(tkMenuCascadeRgn, rgn); + OffsetRgn(rgn, -scratch.h, -scratch.v); + DiffRgn(clipRgn, rgn, clipRgn); + SetPortClipRegion(destPort, clipRgn); + SetEmptyRgn(rgn); + macDraw->toplevel->flags |= TK_DRAWN_UNDER_MENU; + } + + ScrollRect(&scrollRect, dx, dy, rgn); + + SetGWorld(saveWorld, saveDevice); + + DisposeRgn(clipRgn); + DisposeRgn(visRgn); + /* + * Fortunantly, the region returned by ScrollRect is symanticlly + * the same as what we need to return in this function. If the + * region is empty we return zero to denote that no damage was + * created. + */ + if (EmptyRgn(rgn)) { + return 0; + } else { + return 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXSetUpGraphicsPort -- + * + * Set up the graphics port from the given GC. + * + * Results: + * None. + * + * Side effects: + * The current port is adjusted. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXSetUpGraphicsPort( + GC gc, + GWorldPtr destPort) /* GC to apply to current port. */ +{ + RGBColor macColor; + + if (gPenPat == NULL) { + gPenPat = NewPixPat(); + } + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + /* TODO: cache RGBPats for preformace - measure gains... */ + MakeRGBPat(gPenPat, &macColor); + } + + PenNormal(); + if(gc->function == GXxor) { + PenMode(patXor); + } + if (gc->line_width > 1) { + PenSize(gc->line_width, gc->line_width); + } + if (gc->line_style != LineSolid) { + unsigned char *p = (unsigned char *) &(gc->dashes); + /* + * Here the dash pattern should be set in the drawing, + * environment, but I don't know how to do that for the Mac. + * + * p[] is an array of unsigned chars containing the dash list. + * A '\0' indicates the end of this list. + * + * Someone knows how to implement this? If you have a more + * complete implementation of SetUpGraphicsPort() for + * the Mac (or for Windows), please let me know. + * + * Jan Nijtmans + * CMG Arnhem, B.V. + * email: j.nijtmans@chello.nl (private) + * jan.nijtmans@cmg.nl (work) + * url: http://purl.oclc.org/net/nijtmans/ + * + * FIXME: + * This is not possible with QuickDraw line drawing, we either + * have to convert all line drawings to regions, or, on Mac OS X + * we can use CG to draw our lines instead of QuickDraw. + */ + } +} +/* + *---------------------------------------------------------------------- + * + * TkMacOSXSetUpGraphicsPort -- + * + * Set up the graphics port from the given GC. + * + * Results: + * None. + * + * Side effects: + * The current port is adjusted. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXSetUpCGContext( + MacDrawable *macWin, + CGrafPtr destPort, + GC gc, + CGContextRef *contextPtr) /* GC to apply to current port. */ +{ + RGBColor macColor; + CGContextRef outContext; + OSStatus err; + Rect boundsRect; + CGAffineTransform coordsTransform; + + err = QDBeginCGContext(destPort, contextPtr); + outContext = *contextPtr; + + CGContextSaveGState(outContext); + + GetPortBounds(destPort, &boundsRect); + + CGContextResetCTM(outContext); + coordsTransform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0, + (float)(boundsRect.bottom - boundsRect.top)); + CGContextConcatCTM(outContext, coordsTransform); + + if (macWin->clipRgn != NULL) { + ClipCGContextToRegion(outContext, &boundsRect, macWin->clipRgn); + } else { + RgnHandle clipRgn = NewRgn(); + GetPortClipRegion(destPort, clipRgn); + ClipCGContextToRegion(outContext, &boundsRect, + clipRgn); + DisposeRgn(clipRgn); + } + + /* Now offset the CTM to the subwindow offset */ + + CGContextTranslateCTM(outContext, macWin->xOff, macWin->yOff); + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + CGContextSetRGBStrokeColor(outContext, RGBFLOATRED(macColor), + RGBFLOATGREEN(macColor), + RGBFLOATBLUE(macColor), 1.0); + } + if (TkSetMacColor(gc->background, &macColor) == true) { + CGContextSetRGBFillColor(outContext, RGBFLOATRED(macColor), + RGBFLOATGREEN(macColor), + RGBFLOATBLUE(macColor), 1.0); + } + + if(gc->function == GXxor) { + } + + CGContextSetLineWidth(outContext, (float) gc->line_width); + + if (gc->line_style != LineSolid) { + unsigned char *p = (unsigned char *) &(gc->dashes); + /* + * Here the dash pattern should be set in the drawing, + * environment, but I don't know how to do that for the Mac. + * + * p[] is an array of unsigned chars containing the dash list. + * A '\0' indicates the end of this list. + * + * Someone knows how to implement this? If you have a more + * complete implementation of SetUpGraphicsPort() for + * the Mac (or for Windows), please let me know. + * + * Jan Nijtmans + * CMG Arnhem, B.V. + * email: j.nijtmans@chello.nl (private) + * jan.nijtmans@cmg.nl (work) + * url: http://purl.oclc.org/net/nijtmans/ + * + * FIXME: + * This is not possible with QuickDraw line drawing, we either + * have to convert all line drawings to regions, or, on Mac OS X + * we can use CG to draw our lines instead of QuickDraw. + */ + } +} + +void +TkMacOSXReleaseCGContext( + MacDrawable *macWin, + CGrafPtr destPort, + CGContextRef *outContext) +{ + CGContextResetCTM(*outContext); + CGContextRestoreGState(*outContext); + QDEndCGContext(destPort, outContext); + +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXSetUpClippingRgn -- + * + * Set up the clipping region so that drawing only occurs on the + * specified X subwindow. + * + * Results: + * None. + * + * Side effects: + * The clipping region in the current port is changed. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXSetUpClippingRgn( + Drawable drawable) /* Drawable to update. */ +{ + MacDrawable *macDraw = (MacDrawable *) drawable; + + if (macDraw->winPtr != NULL) { + if (macDraw->flags & TK_CLIP_INVALID) { + TkMacOSXUpdateClipRgn(macDraw->winPtr); + } + + /* + * When a menu is up, the Mac does not expect drawing to occur and + * does not clip out the menu. We have to do it ourselves. This + * is pretty gross. + */ + + if (macDraw->clipRgn != NULL) { + if (tkUseMenuCascadeRgn == 1) { + Point scratch = {0, 0}; + GDHandle saveDevice; + GWorldPtr saveWorld; + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(TkMacOSXGetDrawablePort(drawable), NULL); + LocalToGlobal(&scratch); + SetGWorld(saveWorld, saveDevice); + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + CopyRgn(tkMenuCascadeRgn, tmpRgn); + OffsetRgn(tmpRgn, -scratch.h, -scratch.v); + DiffRgn(macDraw->clipRgn, tmpRgn, tmpRgn); + SetClip(tmpRgn); + macDraw->toplevel->flags |= TK_DRAWN_UNDER_MENU; + } else { + SetClip(macDraw->clipRgn); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXMakeStippleMap -- + * + * Given a drawable and a stipple pattern this function draws the + * pattern repeatedly over the drawable. The drawable can then + * be used as a mask for bit-bliting a stipple pattern over an + * object. + * + * Results: + * A BitMap data structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +BitMapPtr +TkMacOSXMakeStippleMap( + Drawable drawable, /* Window to apply stipple. */ + Drawable stipple) /* The stipple pattern. */ +{ + GWorldPtr destPort; + BitMapPtr bitmapPtr; + Rect portRect; + int width, height, stippleHeight, stippleWidth; + int i, j; + char * data; + Rect bounds; + + destPort = TkMacOSXGetDrawablePort(drawable); + + GetPortBounds ( destPort, &portRect ); + width = portRect.right - portRect.left; + height = portRect.bottom - portRect.top; + + bitmapPtr = (BitMap *) ckalloc(sizeof(BitMap)); + data = (char *) ckalloc(height * ((width / 8) + 1)); + bitmapPtr->bounds.top = bitmapPtr->bounds.left = 0; + bitmapPtr->bounds.right = (short) width; + bitmapPtr->bounds.bottom = (short) height; + bitmapPtr->baseAddr = data; + bitmapPtr->rowBytes = (width / 8) + 1; + + destPort = TkMacOSXGetDrawablePort(stipple); + stippleWidth = portRect.right - portRect.left; + stippleHeight = portRect.bottom - portRect.top; + + for (i = 0; i < height; i += stippleHeight) { + for (j = 0; j < width; j += stippleWidth) { + bounds.left = j; + bounds.top = i; + bounds.right = j + stippleWidth; + bounds.bottom = i + stippleHeight; + + CopyBits(GetPortBitMapForCopyBits ( destPort ), bitmapPtr, + &portRect, &bounds, srcCopy, NULL); + } + } + return bitmapPtr; +} + +/* + *---------------------------------------------------------------------- + * + * InvertByte -- + * + * This function reverses the bits in the passed in Byte of data. + * + * Results: + * The incoming byte in reverse bit order. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned char +InvertByte( + unsigned char data) /* Byte of data. */ +{ + unsigned char i; + unsigned char mask = 1, result = 0; + + for (i = (1 << 7); i != 0; i /= 2) { + if (data & mask) { + result |= i; + } + mask = mask << 1; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDrawpHighlightBorder -- + * + * This procedure draws a rectangular ring around the outside of + * a widget to indicate that it has received the input focus. + * + * On the Macintosh, this puts a 1 pixel border in the bgGC color + * between the widget and the focus ring, except in the case where + * highlightWidth is 1, in which case the border is left out. + * + * For proper Mac L&F, use highlightWidth of 3. + * + * Results: + * None. + * + * Side effects: + * A rectangle "width" pixels wide is drawn in "drawable", + * corresponding to the outer area of "tkwin". + * + *---------------------------------------------------------------------- + */ + +void +TkpDrawHighlightBorder ( + Tk_Window tkwin, + GC fgGC, + GC bgGC, + int highlightWidth, + Drawable drawable) +{ + if (highlightWidth == 1) { + TkDrawInsetFocusHighlight (tkwin, fgGC, highlightWidth, drawable, 0); + } else { + TkDrawInsetFocusHighlight (tkwin, bgGC, highlightWidth, drawable, 0); + if (fgGC != bgGC) { + TkDrawInsetFocusHighlight (tkwin, fgGC, highlightWidth - 1, drawable, 0); + } + } +} |