diff options
Diffstat (limited to 'macosx/tkMacOSXDraw.c')
-rw-r--r-- | macosx/tkMacOSXDraw.c | 852 |
1 files changed, 243 insertions, 609 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 66027cd..a7314f1 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1,13 +1,13 @@ /* * tkMacOSXDraw.c -- * - * This file contains functions that perform drawing to Xlib windows. Most - * of the functions simply emulate Xlib functions. + * This file contains functions that draw to windows. Many of thees + * functions emulate Xlib functions. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. - * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2001-2009 Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> - * Copyright 2014 Marc Culler. + * Copyright (c) 2014-2020 Marc Culler. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -17,7 +17,7 @@ #include "tkMacOSXDebug.h" #include "tkButton.h" -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 #define GET_CGCONTEXT [[NSGraphicsContext currentContext] CGContext] #else #define GET_CGCONTEXT [[NSGraphicsContext currentContext] graphicsPort] @@ -43,12 +43,15 @@ static int cgAntiAliasLimit = 0; static int useThemedToplevel = 0; static int useThemedFrame = 0; +static unsigned long transparentColor; /* * Prototypes for functions used only in this file. */ static void ClipToGC(Drawable d, GC gc, HIShapeRef *clipRgnPtr); +static NSImage *CreateNSImageFromPixmap(Pixmap pixmap, int width, int height); + /* *---------------------------------------------------------------------- @@ -69,11 +72,10 @@ static void ClipToGC(Drawable d, GC gc, HIShapeRef *clipRgnPtr); MODULE_SCOPE int TkMacOSXInitCGDrawing( Tcl_Interp *interp, - int enable, + TCL_UNUSED(int), int limit) { static Boolean initialized = FALSE; - (void)enable; if (!initialized) { initialized = TRUE; @@ -83,7 +85,7 @@ TkMacOSXInitCGDrawing( } if (Tcl_LinkVar(interp, "::tk::mac::CGAntialiasLimit", - (char *) &cgAntiAliasLimit, TCL_LINK_INT) != TCL_OK) { + (char *)&cgAntiAliasLimit, TCL_LINK_INT) != TCL_OK) { Tcl_ResetResult(interp); } cgAntiAliasLimit = limit; @@ -93,13 +95,14 @@ TkMacOSXInitCGDrawing( */ if (Tcl_LinkVar(interp, "::tk::mac::useThemedToplevel", - (char *) &useThemedToplevel, TCL_LINK_BOOLEAN) != TCL_OK) { + (char *)&useThemedToplevel, TCL_LINK_BOOLEAN) != TCL_OK) { Tcl_ResetResult(interp); } if (Tcl_LinkVar(interp, "::tk::mac::useThemedFrame", - (char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) { + (char *)&useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) { Tcl_ResetResult(interp); } + transparentColor = TkMacOSXClearPixel(); } return TCL_OK; } @@ -107,382 +110,7 @@ TkMacOSXInitCGDrawing( /* *---------------------------------------------------------------------- * - * TkMacOSXBitmapRepFromDrawableRect - * - * Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep. - * - * This is only used by XGetImage, which is never called. And this - * implementation does not work correctly. Originally it relied on - * [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was - * deprecated by Apple in OSX 10.14 and also required the use of other - * deprecated functions such as [NSView lockFocus]. Apple's suggested - * replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that - * is what is being used here. However, that method only works when the - * view has a valid CGContext, and a view is only guaranteed to have a - * valid context during a call to [NSView drawRect]. To further complicate - * matters, cacheDisplayInRect calls [NSView drawRect]. Essentially it is - * asking the view to draw a subrectangle of itself into a special - * graphics context which is linked to the BitmapImageRep. But our - * implementation of [NSView drawRect] does not allow recursive calls. If - * called recursively it returns immediately without doing any drawing. - * So the bottom line is that this function either returns a NULL pointer - * or a black image. To make it useful would require a significant amount - * of rewriting of the drawRect method. Perhaps the next release of OSX - * will include some more helpful ways of doing this. - * - * Results: - * Returns an NSBitmapRep representing the image of the given rectangle of - * the given drawable. This object is retained. The caller is responsible - * for releasing it. - * - * NOTE: The x,y coordinates should be relative to a coordinate system - * with origin at the top left, as used by XImage and CGImage, not bottom - * left as used by NSView. - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -NSBitmapImageRep * -TkMacOSXBitmapRepFromDrawableRect( - Drawable drawable, - int x, - int y, - unsigned int width, - unsigned int height) -{ - MacDrawable *mac_drawable = (MacDrawable *) drawable; - CGContextRef cg_context = NULL; - CGImageRef cg_image = NULL, sub_cg_image = NULL; - NSBitmapImageRep *bitmap_rep = NULL; - NSView *view = NULL; - if (mac_drawable->flags & TK_IS_PIXMAP) { - /* - * This MacDrawable is a bitmap, so its view is NULL. - */ - - CGRect image_rect = CGRectMake(x, y, width, height); - - cg_context = TkMacOSXGetCGContextForDrawable(drawable); - cg_image = CGBitmapContextCreateImage((CGContextRef) cg_context); - sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect); - if (sub_cg_image) { - bitmap_rep = [NSBitmapImageRep alloc]; - [bitmap_rep initWithCGImage:sub_cg_image]; - } - if (cg_image) { - CGImageRelease(cg_image); - } - } else if ((view = TkMacOSXDrawableView(mac_drawable)) != NULL) { - /* - * Convert Tk top-left to NSView bottom-left coordinates. - */ - - int view_height = [view bounds].size.height; - NSRect view_rect = NSMakeRect(x + mac_drawable->xOff, - view_height - height - y - mac_drawable->yOff, - width, height); - - /* - * Attempt to copy from the view to a bitmapImageRep. If the view does - * not have a valid CGContext, doing this will silently corrupt memory - * and make a big mess. So, in that case, we mark the view as needing - * display and return NULL. - */ - - if (view == [NSView focusView]) { - bitmap_rep = [view bitmapImageRepForCachingDisplayInRect: view_rect]; - [bitmap_rep retain]; - [view cacheDisplayInRect:view_rect toBitmapImageRep:bitmap_rep]; - } else { - TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap."); - [view setNeedsDisplay:YES]; - return NULL; - } - } else { - TkMacOSXDbgMsg("Invalid source drawable"); - } - return bitmap_rep; -} - -/* - *---------------------------------------------------------------------- - * - * XCopyArea -- - * - * Copies data from one drawable to another. - * - * Results: - * None. - * - * Side effects: - * Data is moved from a window or bitmap to a second window or bitmap. - * - *---------------------------------------------------------------------- - */ - -int -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, /* that will be copied. */ - unsigned int height, - int dest_x, /* Dest X & Y on dest rect. */ - int dest_y) -{ - TkMacOSXDrawingContext dc; - MacDrawable *srcDraw = (MacDrawable *) src; - NSBitmapImageRep *bitmap_rep = NULL; - CGImageRef img = NULL; - CGRect bounds, srcRect, dstRect; - - display->request++; - if (!width || !height) { - return BadDrawable; - } - - if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - TkMacOSXDbgMsg("Failed to setup drawing context."); - return BadDrawable; - } - - if (!dc.context) { - TkMacOSXDbgMsg("Invalid destination drawable - no context."); - return BadDrawable; - } - - if (srcDraw->flags & TK_IS_PIXMAP) { - img = TkMacOSXCreateCGImageWithDrawable(src); - } else if (TkMacOSXDrawableWindow(src)) { - bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src, - src_x, src_y, width, height); - if (bitmap_rep) { - img = [bitmap_rep CGImage]; - } - } else { - TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap."); - } - - if (img) { - bounds = CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height); - srcRect = CGRectMake(src_x, src_y, width, height); - dstRect = CGRectMake(dest_x, dest_y, width, height); - TkMacOSXDrawCGImage(dst, gc, dc.context, img, - gc->foreground, gc->background, bounds, srcRect, dstRect); - CFRelease(img); - } else { - TkMacOSXDbgMsg("Failed to construct CGImage."); - } - - TkMacOSXRestoreDrawingContext(&dc); - return Success; -} - -/* - *---------------------------------------------------------------------- - * - * 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. - * - *---------------------------------------------------------------------- - */ - -int -XCopyPlane( - 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, /* that will be copied. */ - unsigned int height, - int dest_x, /* Dest X & Y on dest rect. */ - int dest_y, - unsigned long plane) /* Which plane to copy. */ -{ - TkMacOSXDrawingContext dc; - MacDrawable *srcDraw = (MacDrawable *) src; - MacDrawable *dstDraw = (MacDrawable *) dst; - CGRect bounds, srcRect, dstRect; - display->request++; - if (!width || !height) { - /* TkMacOSXDbgMsg("Drawing of empty area requested"); */ - return BadDrawable; - } - if (plane != 1) { - Tcl_Panic("Unexpected plane specified for XCopyPlane"); - } - if (srcDraw->flags & TK_IS_PIXMAP) { - if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - return BadDrawable; - } - - CGContextRef context = dc.context; - - if (context) { - CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src); - - if (img) { - TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask; - unsigned long imageBackground = gc->background; - - if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP) { - srcRect = CGRectMake(src_x, src_y, width, height); - CGImageRef mask = TkMacOSXCreateCGImageWithDrawable( - clipPtr->value.pixmap); - CGImageRef submask = CGImageCreateWithImageInRect( - img, srcRect); - CGRect rect = CGRectMake(dest_x, dest_y, width, height); - - rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff); - CGContextSaveGState(context); - - /* - * Move the origin of the destination to top left. - */ - - CGContextTranslateCTM(context, - 0, rect.origin.y + CGRectGetMaxY(rect)); - CGContextScaleCTM(context, 1, -1); - - /* - * Fill with the background color, clipping to the mask. - */ - - CGContextClipToMask(context, rect, submask); - TkMacOSXSetColorInContext(gc, gc->background, dc.context); - CGContextFillRect(context, rect); - - /* - * Fill with the foreground color, clipping to the - * intersection of img and mask. - */ - - CGImageRef subimage = CGImageCreateWithImageInRect( - img, srcRect); - CGContextClipToMask(context, rect, subimage); - TkMacOSXSetColorInContext(gc, gc->foreground, context); - CGContextFillRect(context, rect); - CGContextRestoreGState(context); - CGImageRelease(img); - CGImageRelease(mask); - CGImageRelease(submask); - CGImageRelease(subimage); - } else { - bounds = CGRectMake(0, 0, - srcDraw->size.width, srcDraw->size.height); - srcRect = CGRectMake(src_x, src_y, width, height); - dstRect = CGRectMake(dest_x, dest_y, width, height); - TkMacOSXDrawCGImage(dst, gc, dc.context, img, - gc->foreground, imageBackground, bounds, - srcRect, dstRect); - CGImageRelease(img); - } - } else { - /* no image */ - TkMacOSXDbgMsg("Invalid source drawable"); - } - } else { - TkMacOSXDbgMsg("Invalid destination drawable - " - "could not get a bitmap context."); - } - TkMacOSXRestoreDrawingContext(&dc); - return Success; - } else { - /* - * Source drawable is a Window, not a Pixmap. - */ - - return XCopyArea(display, src, dst, gc, src_x, src_y, width, height, - dest_x, dest_y); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXCreateCGImageWithDrawable -- - * - * Create a CGImage from the given Drawable. - * - * Results: - * CGImage, release after use. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -CGImageRef -TkMacOSXCreateCGImageWithDrawable( - Drawable drawable) -{ - CGImageRef img = NULL; - CGContextRef context = TkMacOSXGetCGContextForDrawable(drawable); - - if (context) { - img = CGBitmapContextCreateImage(context); - } - return img; -} - -/* - *---------------------------------------------------------------------- - * - * CreateNSImageWithPixmap -- - * - * Create NSImage for Pixmap. - * - * Results: - * NSImage. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static NSImage * -CreateNSImageWithPixmap( - Pixmap pixmap, - int width, - int height) -{ - CGImageRef cgImage; - NSImage *nsImage; - NSBitmapImageRep *bitmapImageRep; - - cgImage = TkMacOSXCreateCGImageWithDrawable(pixmap); - nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; - [nsImage addRepresentation:bitmapImageRep]; - [bitmapImageRep release]; - CFRelease(cgImage); - - return nsImage; -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXGetNSImageWithTkImage -- + * TkMacOSXGetNSImageFromTkImage -- * * Get autoreleased NSImage for Tk_Image. * @@ -496,7 +124,7 @@ CreateNSImageWithPixmap( */ NSImage * -TkMacOSXGetNSImageWithTkImage( +TkMacOSXGetNSImageFromTkImage( Display *display, Tk_Image image, int width, @@ -509,7 +137,7 @@ TkMacOSXGetNSImageWithTkImage( } pixmap = Tk_GetPixmap(display, None, width, height, 0); Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0); - nsImage = CreateNSImageWithPixmap(pixmap, width, height); + nsImage = CreateNSImageFromPixmap(pixmap, width, height); Tk_FreePixmap(display, pixmap); return [nsImage autorelease]; @@ -518,7 +146,7 @@ TkMacOSXGetNSImageWithTkImage( /* *---------------------------------------------------------------------- * - * TkMacOSXGetNSImageWithBitmap -- + * TkMacOSXGetNSImageFromBitmap -- * * Get autoreleased NSImage for Bitmap. * @@ -532,7 +160,7 @@ TkMacOSXGetNSImageWithTkImage( */ NSImage * -TkMacOSXGetNSImageWithBitmap( +TkMacOSXGetNSImageFromBitmap( Display *display, Pixmap bitmap, GC gc, @@ -544,11 +172,11 @@ TkMacOSXGetNSImageWithBitmap( unsigned long origBackground = gc->background; - gc->background = TRANSPARENT_PIXEL << 24; + gc->background = transparentColor; XSetClipOrigin(display, gc, 0, 0); XCopyPlane(display, bitmap, pixmap, gc, 0, 0, width, height, 0, 0, 1); gc->background = origBackground; - nsImage = CreateNSImageWithPixmap(pixmap, width, height); + nsImage = CreateNSImageFromPixmap(pixmap, width, height); Tk_FreePixmap(display, pixmap); return [nsImage autorelease]; @@ -557,7 +185,48 @@ TkMacOSXGetNSImageWithBitmap( /* *---------------------------------------------------------------------- * - * TkMacOSXGetCGContextForDrawable -- + * CreateNSImageFromPixmap -- + * + * Create NSImage for Pixmap. + * + * Results: + * NSImage. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static NSImage * +CreateNSImageFromPixmap( + Pixmap pixmap, + int width, + int height) +{ + CGImageRef cgImage; + NSImage *nsImage; + NSBitmapImageRep *bitmapImageRep; + CGContextRef context = TkMacOSXGetCGContextForDrawable(pixmap); + + if (context) { + cgImage = CGBitmapContextCreateImage(context); + } else { + return NULL; + } + nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + [nsImage addRepresentation:bitmapImageRep]; + [bitmapImageRep release]; + CFRelease(cgImage); + + return nsImage; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_MacOSXGetCGContextForDrawable -- * * Get CGContext for given Drawable, creating one if necessary. * @@ -570,11 +239,11 @@ TkMacOSXGetNSImageWithBitmap( *---------------------------------------------------------------------- */ -CGContextRef -TkMacOSXGetCGContextForDrawable( +void * +Tk_MacOSXGetCGContextForDrawable( Drawable drawable) { - MacDrawable *macDraw = (MacDrawable *) drawable; + MacDrawable *macDraw = (MacDrawable *)drawable; if (macDraw && (macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) { const size_t bitsPerComponent = 8; @@ -592,7 +261,7 @@ TkMacOSXGetCGContextForDrawable( if (macDraw->flags & TK_IS_BW_PIXMAP) { bitsPerPixel = 8; - bitmapInfo = (CGBitmapInfo) kCGImageAlphaOnly; + bitmapInfo = (CGBitmapInfo)kCGImageAlphaOnly; } else { colorspace = CGColorSpaceCreateDeviceRGB(); bitsPerPixel = 32; @@ -645,7 +314,7 @@ TkMacOSXDrawCGImage( CGRect srcBounds, CGRect dstBounds) { - MacDrawable *macDraw = (MacDrawable *) d; + MacDrawable *macDraw = (MacDrawable *)d; if (macDraw && context && image) { CGImageRef subImage = NULL; @@ -663,17 +332,18 @@ TkMacOSXDrawCGImage( dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); if (CGImageIsMask(image)) { if (macDraw->flags & TK_IS_BW_PIXMAP) { + /* * Set fill color to black; background comes from the context, * or is transparent. */ - if (imageBackground != TRANSPARENT_PIXEL << 24) { + if (imageBackground != transparentColor) { CGContextClearRect(context, dstBounds); } CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0); } else { - if (imageBackground != TRANSPARENT_PIXEL << 24) { + if (imageBackground != transparentColor) { TkMacOSXSetColorInContext(gc, imageBackground, context); CGContextFillRect(context, dstBounds); } @@ -740,7 +410,7 @@ XDrawLines( int npoints, /* Number of points. */ int mode) /* Line drawing mode. */ { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; int i, lw = gc->line_width; @@ -749,7 +419,7 @@ XDrawLines( } display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -812,12 +482,12 @@ XDrawSegments( XSegment *segments, int nsegments) { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; int i, lw = gc->line_width; display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -861,16 +531,15 @@ XFillPolygon( GC gc, /* Use this GC. */ XPoint *points, /* Array of points. */ int npoints, /* Number of points. */ - int shape, /* Shape to draw. */ + TCL_UNUSED(int), /* Shape to draw. */ int mode) /* Drawing mode. */ { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; int i; - (void)shape; display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -923,7 +592,7 @@ XDrawRectangle( unsigned int width, /* Width & height of rect. */ unsigned int height) { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; int lw = gc->line_width; @@ -932,7 +601,7 @@ XDrawRectangle( } display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -975,18 +644,18 @@ XDrawRectangle( int XDrawRectangles( Display *display, - Drawable drawable, + Drawable d, GC gc, XRectangle *rectArr, int nRects) { - MacDrawable *macWin = (MacDrawable *) drawable; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; XRectangle * rectPtr; int i, lw = gc->line_width; display->request++; - if (!TkMacOSXSetupDrawingContext(drawable, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -1032,13 +701,13 @@ XFillRectangles( XRectangle *rectangles, /* Rectangle array. */ int n_rectangles) /* Number of rectangles. */ { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; XRectangle * rectPtr; int i; display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -1091,7 +760,7 @@ TkMacOSXDrawSolidBorder( TkMacOSXDrawingContext dc; CGRect outerRect, innerRect; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return; } if (dc.context) { @@ -1134,7 +803,7 @@ XDrawArc( int angle1, /* Staring angle of arc. */ int angle2) /* Extent of arc. */ { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; int lw = gc->line_width; @@ -1143,7 +812,7 @@ XDrawArc( } display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -1207,13 +876,13 @@ XDrawArcs( XArc *arcArr, int nArcs) { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; XArc *arcPtr; int i, lw = gc->line_width; display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -1285,7 +954,7 @@ XFillArc( int angle1, /* Staring angle of arc. */ int angle2) /* Extent of arc. */ { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; int lw = gc->line_width; @@ -1294,7 +963,7 @@ XFillArc( } display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -1361,13 +1030,13 @@ XFillArcs( XArc *arcArr, int nArcs) { - MacDrawable *macWin = (MacDrawable *) d; + MacDrawable *macWin = (MacDrawable *)d; TkMacOSXDrawingContext dc; XArc * arcPtr; int i, lw = gc->line_width; display->request++; - if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { + if (!TkMacOSXSetupDrawingContext(d, gc, &dc)) { return BadDrawable; } if (dc.context) { @@ -1440,20 +1109,19 @@ XFillArcs( int TkScrollWindow( Tk_Window tkwin, /* The window to be scrolled. */ - GC gc, /* GC for window to be scrolled. */ + TCL_UNUSED(GC), /* GC for window to be scrolled. */ int x, int y, /* Position rectangle to be scrolled. */ int width, int height, int dx, int dy, /* Distance rectangle should be moved. */ Region damageRgn) /* Region to accumulate damage in. */ { Drawable drawable = Tk_WindowId(tkwin); - MacDrawable *macDraw = (MacDrawable *) drawable; - TKContentView *view = (TKContentView *) TkMacOSXDrawableView(macDraw); + MacDrawable *macDraw = (MacDrawable *)drawable; + TKContentView *view = (TKContentView *)TkMacOSXGetNSViewForDrawable(macDraw); CGRect srcRect, dstRect; HIShapeRef dmgRgn = NULL, extraRgn = NULL; NSRect bounds, visRect, scrollSrc, scrollDst; int result = 0; - (void)gc; if (view) { /* @@ -1537,12 +1205,9 @@ TkScrollWindow( void TkMacOSXSetUpGraphicsPort( - GC gc, /* GC to apply to current port. */ - void *destPort) + TCL_UNUSED(GC), /* GC to apply to current port. */ + TCL_UNUSED(void *)) { - (void)gc; - (void)destPort; - Tcl_Panic("TkMacOSXSetUpGraphicsPort: Obsolete, no more QD!"); } @@ -1552,15 +1217,17 @@ TkMacOSXSetUpGraphicsPort( * * TkMacOSXSetUpDrawingContext -- * - * Set up a drawing context for the given drawable and GC. + * Set up a drawing context for the given drawable from an X GC. * * Results: - * Boolean indicating whether it is ok to draw; if false, drawing context - * was not setup, so do not attempt to draw and do not call + * Boolean indicating whether it is ok to draw; if false, the drawing + * context was not setup, so do not attempt to draw and do not call * TkMacOSXRestoreDrawingContext(). * * Side effects: - * None. + * May modify or create the drawable's graphics context. May expand the + * drawable's dirty rectangle. When the result is true The dcPtr + * parameter is set to reference the new or updated drawing context. * *---------------------------------------------------------------------- */ @@ -1569,27 +1236,28 @@ Bool TkMacOSXSetupDrawingContext( Drawable d, GC gc, - int useCG, /* advisory only ! */ TkMacOSXDrawingContext *dcPtr) { - MacDrawable *macDraw = (MacDrawable *) d; + MacDrawable *macDraw = (MacDrawable *)d; Bool canDraw = true; - NSWindow *win = NULL; + TKContentView *view = nil; TkMacOSXDrawingContext dc = {}; - CGRect clipBounds; - (void)useCG; /* - * If the drawable is not a pixmap and it has an associated NSWindow then - * we know we are drawing to a window. + * If the drawable is not a pixmap, get the associated NSView. */ if (!(macDraw->flags & TK_IS_PIXMAP)) { - win = TkMacOSXDrawableWindow(d); + view = (TKContentView *)TkMacOSXGetNSViewForDrawable(d); + if (!view) { + Tcl_Panic("TkMacOSXSetupDrawingContext(): " + "no NSView to draw into !"); + } } /* - * Check that we have a non-empty clipping region. + * Intersect the drawable's clipping region with the region stored in the + * X GC. If the resulting region is empty, don't do any drawing. */ dc.clipRgn = TkMacOSXGetClipRgn(d); @@ -1600,165 +1268,158 @@ TkMacOSXSetupDrawingContext( } /* - * If we already have a CGContext, use it. Otherwise, if we are drawing to - * a window then we can get one from the window. + * If the drawable already has a CGContext, use it. Otherwise, we must be + * drawing to a window and we use the current context of its ContentView. */ dc.context = TkMacOSXGetCGContextForDrawable(d); if (dc.context) { - dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context); - } else if (win) { - NSView *view = TkMacOSXDrawableView(macDraw); + dc.portBounds = CGContextGetClipBoundingBox(dc.context); + } else { + NSRect drawingBounds, currentBounds; - if (!view) { - Tcl_Panic("TkMacOSXSetupDrawingContext(): " - "no NSView to draw into !"); + dc.view = view; + dc.context = GET_CGCONTEXT; + dc.portBounds = NSRectToCGRect([view bounds]); + if (dc.clipRgn) { + CGRect clipBounds; + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, + .ty = [view bounds].size.height}; + HIShapeGetBounds(dc.clipRgn, &clipBounds); + clipBounds = CGRectApplyAffineTransform(clipBounds, t); + drawingBounds = NSRectFromCGRect(clipBounds); + } else { + drawingBounds = [view bounds]; } /* - * We can only draw into the view when the current CGContext is valid - * and belongs to the view. Validity can only be guaranteed inside of - * a view's drawRect or setFrame methods. The isDrawing attribute - * tells us whether we are being called from one of those methods. - * - * If the CGContext is not valid then we mark our view as needing - * display in the bounding rectangle of the clipping region and - * return failure. That rectangle should get drawn in a later call - * to drawRect. - * - * As an exception to the above, if mouse buttons are pressed at the - * moment when we fail to obtain a valid context we schedule the entire - * view for a redraw rather than just the clipping region. The purpose - * of this is to make sure that scrollbars get updated correctly. + * We can only draw into the NSView which is the current focusView. + * When the current [NSView focusView] is nil, the CGContext for + * [NSGraphicsContext currentContext] is nil. Otherwise the current + * CGContext draws into the current focusView. An NSView is guaranteed + * to be the focusView when its drawRect or setFrame methods are + * running. Prior to OSX 10.14 it was also possible to call the + * lockFocus method to force an NSView to become the current focusView. + * But that method was deprecated in 10.14 and so is no longer used by + * Tk. Instead, if the view is not the current focusView then we add + * the drawing bounds to its dirty rectangle and return false. The + * part of the view inside the drawing bounds will get redrawn during + * the next call to its drawRect method. */ - if (![NSApp isDrawing] || view != [NSView focusView]) { - NSRect bounds = [view bounds]; - NSRect dirtyNS = bounds; - if ([NSEvent pressedMouseButtons]) { - [view setNeedsDisplay:YES]; - } else { - CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = dirtyNS.size.height}; - if (dc.clipRgn) { - CGRect dirtyCG = NSRectToCGRect(dirtyNS); - HIShapeGetBounds(dc.clipRgn, &dirtyCG); - dirtyNS = NSRectToCGRect(CGRectApplyAffineTransform(dirtyCG, t)); - } - [view setNeedsDisplayInRect:dirtyNS]; - } + if (view != [NSView focusView]) { + [view addTkDirtyRect:drawingBounds]; canDraw = false; goto end; } - dc.view = view; - dc.context = GET_CGCONTEXT; - dc.portBounds = NSRectToCGRect([view bounds]); - if (dc.clipRgn) { - clipBounds = CGContextGetClipBoundingBox(dc.context); + /* + * Drawing will also fail when the view is the current focusView but + * the clipping rectangle set by drawRect does not contain the clipping + * region of our drawing context. (See bug [2a61eca3a8].) If part of + * the drawing bounds will be clipped then we draw whatever we can, but + * we also add the drawing bounds to the view's dirty rectangle so it + * will get redrawn in the next call to its drawRect method. + */ + + currentBounds = CGContextGetClipBoundingBox(dc.context); + if (!NSContainsRect(currentBounds, drawingBounds)) { + [view addTkDirtyRect:drawingBounds]; } - } else { - Tcl_Panic("TkMacOSXSetupDrawingContext(): " - "no context to draw into !"); } /* - * Configure the drawing context. + * Finish configuring the drawing context. */ - if (dc.context) { - CGAffineTransform t = { - .a = 1, .b = 0, - .c = 0, .d = -1, - .tx = 0, - .ty = dc.portBounds.size.height - }; + CGAffineTransform t = { + .a = 1, .b = 0, + .c = 0, .d = -1, + .tx = 0, + .ty = dc.portBounds.size.height + }; + + dc.portBounds.origin.x += macDraw->xOff; + dc.portBounds.origin.y += macDraw->yOff; + CGContextSaveGState(dc.context); + CGContextSetTextDrawingMode(dc.context, kCGTextFill); + CGContextConcatCTM(dc.context, t); + if (dc.clipRgn) { - dc.portBounds.origin.x += macDraw->xOff; - dc.portBounds.origin.y += macDraw->yOff; - CGContextSaveGState(dc.context); - CGContextSetTextDrawingMode(dc.context, kCGTextFill); - CGContextConcatCTM(dc.context, t); - if (dc.clipRgn) { #ifdef TK_MAC_DEBUG_DRAWING - CGContextSaveGState(dc.context); - ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); - CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1); - CGContextEOFillPath(dc.context); - CGContextRestoreGState(dc.context); + CGContextSaveGState(dc.context); + ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); + CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1); + CGContextEOFillPath(dc.context); + CGContextRestoreGState(dc.context); #endif /* TK_MAC_DEBUG_DRAWING */ - CGRect r; - if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect( - *HIShapeGetBounds(dc.clipRgn, &r), - CGRectApplyAffineTransform(clipBounds, t))) { - ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); - CGContextEOClip(dc.context); - } + CGRect r; + CGRect b = CGRectApplyAffineTransform( + CGContextGetClipBoundingBox(dc.context), t); + if (!HIShapeIsRectangular(dc.clipRgn) || + !CGRectContainsRect(*HIShapeGetBounds(dc.clipRgn, &r), b)) { + ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); + CGContextEOClip(dc.context); } - if (gc) { - static const CGLineCap cgCap[] = { - [CapNotLast] = kCGLineCapButt, - [CapButt] = kCGLineCapButt, - [CapRound] = kCGLineCapRound, - [CapProjecting] = kCGLineCapSquare, - }; - static const CGLineJoin cgJoin[] = { - [JoinMiter] = kCGLineJoinMiter, - [JoinRound] = kCGLineJoinRound, - [JoinBevel] = kCGLineJoinBevel, - }; - bool shouldAntialias; - double w = gc->line_width; - - TkMacOSXSetColorInContext(gc, gc->foreground, dc.context); - if (win) { - CGContextSetPatternPhase(dc.context, CGSizeMake( - dc.portBounds.size.width, dc.portBounds.size.height)); - } - if (gc->function != GXcopy) { - TkMacOSXDbgMsg("Logical functions other than GXcopy are " - "not supported for CG drawing!"); - } + } + if (gc) { + static const CGLineCap cgCap[] = { + [CapNotLast] = kCGLineCapButt, + [CapButt] = kCGLineCapButt, + [CapRound] = kCGLineCapRound, + [CapProjecting] = kCGLineCapSquare, + }; + static const CGLineJoin cgJoin[] = { + [JoinMiter] = kCGLineJoinMiter, + [JoinRound] = kCGLineJoinRound, + [JoinBevel] = kCGLineJoinBevel, + }; + bool shouldAntialias = !notAA(gc->line_width); + double w = gc->line_width; + + TkMacOSXSetColorInContext(gc, gc->foreground, dc.context); + if (view) { + CGContextSetPatternPhase(dc.context, CGSizeMake( + dc.portBounds.size.width, dc.portBounds.size.height)); + } + if (gc->function != GXcopy) { + TkMacOSXDbgMsg("Logical functions other than GXcopy are " + "not supported for CG drawing!"); + } + if (!shouldAntialias) { /* - * When should we antialias? + * Make non-antialiased CG drawing look more like X11. */ - shouldAntialias = !notAA(gc->line_width); - if (!shouldAntialias) { - /* - * Make non-antialiased CG drawing look more like X11. - */ - - w -= (gc->line_width ? NON_AA_CG_OFFSET : 0); - } - CGContextSetShouldAntialias(dc.context, shouldAntialias); - CGContextSetLineWidth(dc.context, w); - if (gc->line_style != LineSolid) { - int num = 0; - char *p = &gc->dashes; - CGFloat dashOffset = gc->dash_offset; - CGFloat lengths[10]; - - while (p[num] != '\0' && num < 10) { - lengths[num] = p[num]; - num++; - } - CGContextSetLineDash(dc.context, dashOffset, lengths, num); - } - if ((unsigned) gc->cap_style < sizeof(cgCap)/sizeof(CGLineCap)) { - CGContextSetLineCap(dc.context, - cgCap[(unsigned) gc->cap_style]); - } - if ((unsigned)gc->join_style < sizeof(cgJoin)/sizeof(CGLineJoin)) { - CGContextSetLineJoin(dc.context, - cgJoin[(unsigned) gc->join_style]); + w -= (gc->line_width ? NON_AA_CG_OFFSET : 0); + } + CGContextSetShouldAntialias(dc.context, shouldAntialias); + CGContextSetLineWidth(dc.context, w); + if (gc->line_style != LineSolid) { + int num = 0; + char *p = &gc->dashes; + CGFloat dashOffset = gc->dash_offset; + dashOffset -= (gc->line_width % 2) ? 0.5 : 0.0; + CGFloat lengths[10]; + + while (p[num] != '\0' && num < 10) { + lengths[num] = p[num]; + num++; } + CGContextSetLineDash(dc.context, dashOffset, lengths, num); + } + if ((unsigned) gc->cap_style < sizeof(cgCap)/sizeof(CGLineCap)) { + CGContextSetLineCap(dc.context, cgCap[(unsigned) gc->cap_style]); + } + if ((unsigned)gc->join_style < sizeof(cgJoin)/sizeof(CGLineJoin)) { + CGContextSetLineJoin(dc.context, cgJoin[(unsigned) gc->join_style]); } } end: + #ifdef TK_MAC_DEBUG_DRAWING if (!canDraw && win != NULL) { TkWindow *winPtr = TkMacOSXGetTkWindow(win); @@ -1769,6 +1430,7 @@ end: } } #endif + if (!canDraw && dc.clipRgn) { CFRelease(dc.clipRgn); dc.clipRgn = NULL; @@ -1830,7 +1492,7 @@ HIShapeRef TkMacOSXGetClipRgn( Drawable drawable) /* Drawable. */ { - MacDrawable *macDraw = (MacDrawable *) drawable; + MacDrawable *macDraw = (MacDrawable *)drawable; HIShapeRef clipRgn = NULL; if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { @@ -1838,7 +1500,7 @@ TkMacOSXGetClipRgn( #ifdef TK_MAC_DEBUG_DRAWING TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName); - NSView *view = TkMacOSXDrawableView(macDraw); + NSView *view = TkMacOSXGetNSViewForDrawable(macDraw); CGContextRef context = GET_CGCONTEXT; CGContextSaveGState(context); @@ -1862,30 +1524,6 @@ TkMacOSXGetClipRgn( /* *---------------------------------------------------------------------- * - * TkMacOSXSetUpClippingRgn -- - * - * Set up the clipping region so that drawing only occurs on the specified - * X subwindow. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TkMacOSXSetUpClippingRgn( - Drawable drawable) /* Drawable to update. */ -{ - (void)drawable; -} - -/* - *---------------------------------------------------------------------- - * * TkpClipDrawableToRect -- * * Clip all drawing into the drawable d to the given rectangle. If width @@ -1902,13 +1540,12 @@ TkMacOSXSetUpClippingRgn( void TkpClipDrawableToRect( - Display *display, + TCL_UNUSED(Display *), Drawable d, int x, int y, int width, int height) { - MacDrawable *macDraw = (MacDrawable *) d; - (void)display; + MacDrawable *macDraw = (MacDrawable *)d; if (macDraw->drawRgn) { CFRelease(macDraw->drawRgn); @@ -1955,10 +1592,10 @@ ClipToGC( HIShapeRef *clipRgnPtr) /* must point to initialized variable */ { if (gc && gc->clip_mask && - ((TkpClipMask *) gc->clip_mask)->type == TKP_CLIP_REGION) { - Region gcClip = ((TkpClipMask *) gc->clip_mask)->value.region; - int xOffset = ((MacDrawable *) d)->xOff + gc->clip_x_origin; - int yOffset = ((MacDrawable *) d)->yOff + gc->clip_y_origin; + ((TkpClipMask *)gc->clip_mask)->type == TKP_CLIP_REGION) { + Region gcClip = ((TkpClipMask *)gc->clip_mask)->value.region; + int xOffset = ((MacDrawable *)d)->xOff + gc->clip_x_origin; + int yOffset = ((MacDrawable *)d)->yOff + gc->clip_y_origin; HIShapeRef clipRgn = *clipRgnPtr, gcClipRgn; XOffsetRegion(gcClip, xOffset, yOffset); @@ -1994,12 +1631,9 @@ ClipToGC( void * TkMacOSXMakeStippleMap( - Drawable drawable, /* Window to apply stipple. */ - Drawable stipple) /* The stipple pattern. */ + TCL_UNUSED(Drawable), /* Window to apply stipple. */ + TCL_UNUSED(Drawable)) /* The stipple pattern. */ { - (void)drawable; - (void)stipple; - return NULL; } |