Imported Tk 8.6.9

This commit is contained in:
Steve Dower
2018-12-11 10:05:28 -08:00
parent 753ac6b037
commit 5ba5cbc9af
184 changed files with 6223 additions and 1994 deletions

View File

@@ -18,6 +18,12 @@
#include "tkMacOSXDebug.h"
#include "tkButton.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
#define GET_CGCONTEXT [[NSGraphicsContext currentContext] CGContext]
#else
#define GET_CGCONTEXT [[NSGraphicsContext currentContext] graphicsPort]
#endif
/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_DRAWING
@@ -105,6 +111,25 @@ TkMacOSXInitCGDrawing(
*
* 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.
@@ -128,15 +153,16 @@ TkMacOSXBitmapRepFromDrawableRect(
unsigned int height)
{
MacDrawable *mac_drawable = (MacDrawable *) drawable;
CGContextRef cg_context=NULL;
CGImageRef cg_image=NULL, sub_cg_image=NULL;
NSBitmapImageRep *bitmap_rep=NULL;
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 means that the MacDrawable is functioning as a
* Tk Pixmap, so its view field is NULL.
*/
* This MacDrawable is a bitmap, so its view is NULL.
*/
cg_context = TkMacOSXGetCGContextForDrawable(drawable);
CGRect image_rect = CGRectMake(x, y, width, height);
cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context);
@@ -149,22 +175,32 @@ TkMacOSXBitmapRepFromDrawableRect(
CGImageRelease(cg_image);
}
} else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) {
/*
* 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);
if ( [view lockFocusIfCanDraw] ) {
bitmap_rep = [NSBitmapImageRep alloc];
bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect];
[view unlockFocus];
} else {
TkMacOSXDbgMsg("Could not lock focus on view.");
}
/*
* 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");
}
@@ -205,26 +241,24 @@ XCopyArea(
MacDrawable *srcDraw = (MacDrawable *) src;
NSBitmapImageRep *bitmap_rep = NULL;
CGImageRef img = NULL;
CGRect bounds, srcRect, dstRect;
display->request++;
if (!width || !height) {
/* This happens all the time.
TkMacOSXDbgMsg("Drawing of empty area requested");
*/
return;
}
if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
return;
/*TkMacOSXDbgMsg("Failed to setup drawing context.");*/
TkMacOSXDbgMsg("Failed to setup drawing context.");
}
if ( dc.context ) {
if (srcDraw->flags & TK_IS_PIXMAP) {
img = TkMacOSXCreateCGImageWithDrawable(src);
}else if (TkMacOSXDrawableWindow(src)) {
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src, src_x, src_y, width, height);
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(src,
src_x, src_y, width, height);
if ( bitmap_rep ) {
img = [bitmap_rep CGImage];
}
@@ -233,13 +267,12 @@ XCopyArea(
}
if (img) {
TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background,
CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
CGRectMake(src_x, src_y, width, height),
CGRectMake(dest_x, dest_y, width, height));
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.");
}
@@ -288,7 +321,7 @@ XCopyPlane(
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"); */
@@ -308,7 +341,7 @@ XCopyPlane(
TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
unsigned long imageBackground = gc->background;
if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){
CGRect srcRect = CGRectMake(src_x, src_y, width, height);
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);
@@ -333,10 +366,11 @@ XCopyPlane(
CGImageRelease(submask);
CGImageRelease(subimage);
} else {
TkMacOSXDrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground,
CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
CGRectMake(src_x, src_y, width, height),
CGRectMake(dest_x, dest_y, width, height));
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 */
@@ -440,10 +474,8 @@ TkMacOSXGetNSImageWithTkImage(
int height)
{
Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
MacDrawable *macDraw = (MacDrawable *) pixmap;
NSImage *nsImage;
macDraw->flags |= TK_USE_XIMAGE_ALPHA;
Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0);
nsImage = CreateNSImageWithPixmap(pixmap, width, height);
Tk_FreePixmap(display, pixmap);
@@ -596,11 +628,13 @@ TkMacOSXDrawCGImage(
}
}
dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff);
if (CGImageIsMask(image)) {
/*CGContextSaveGState(context);*/
if (macDraw->flags & TK_IS_BW_PIXMAP) {
/* Set fill color to black, background comes from the context, or is transparent. */
/* Set fill color to black; background comes from the context,
* or is transparent.
*/
if (imageBackground != TRANSPARENT_PIXEL << 24) {
CGContextClearRect(context, dstBounds);
}
@@ -1448,7 +1482,7 @@ TkMacOSXSetUpGraphicsPort(
*----------------------------------------------------------------------
*/
int
Bool
TkMacOSXSetupDrawingContext(
Drawable d,
GC gc,
@@ -1456,41 +1490,71 @@ TkMacOSXSetupDrawingContext(
TkMacOSXDrawingContext *dcPtr)
{
MacDrawable *macDraw = ((MacDrawable*)d);
int dontDraw = 0, isWin = 0;
Bool canDraw = true;
NSWindow *win = NULL;
TkMacOSXDrawingContext dc = {};
CGRect clipBounds;
dc.clipRgn = TkMacOSXGetClipRgn(d);
if (!dontDraw) {
ClipToGC(d, gc, &dc.clipRgn);
dontDraw = dc.clipRgn ? HIShapeIsEmpty(dc.clipRgn) : 0;
/*
* If we are simulating drawing for tests, just return false.
*/
if ([NSApp simulateDrawing]) {
return false;
}
if (dontDraw) {
/*
* If the drawable is not a pixmap and it has an associated
* NSWindow then we know we are drawing to a window.
*/
if (!(macDraw->flags & TK_IS_PIXMAP)) {
win = TkMacOSXDrawableWindow(d);
}
/*
* Check that we have a non-empty clipping region.
*/
dc.clipRgn = TkMacOSXGetClipRgn(d);
ClipToGC(d, gc, &dc.clipRgn);
if (dc.clipRgn && HIShapeIsEmpty(dc.clipRgn)) {
canDraw = false;
goto end;
}
if (useCG) {
dc.context = TkMacOSXGetCGContextForDrawable(d);
}
if (!dc.context || !(macDraw->flags & TK_IS_PIXMAP)) {
isWin = (TkMacOSXDrawableWindow(d) != nil);
}
/*
* If we already have a CGContext, use it. Otherwise, if we
* are drawing to a window then we can get one from the
* window.
*/
dc.context = TkMacOSXGetCGContextForDrawable(d);
if (dc.context) {
dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context);
} else if (isWin) {
} else if (win) {
NSView *view = TkMacOSXDrawableView(macDraw);
if (view) {
if (view != [NSView focusView]) {
dc.focusLocked = [view lockFocusIfCanDraw];
dontDraw = !dc.focusLocked;
} else {
dontDraw = ![view canDraw];
}
if (dontDraw) {
goto end;
}
[[view window] disableFlushWindow];
/*
* 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, or belongs to a different View,
* then we mark our view as needing display and return failure.
* It should get drawn in a later call to drawRect.
*/
if (view != [NSView focusView]) {
[view setNeedsDisplay:YES];
canDraw = false;
goto end;
}
dc.view = view;
dc.context = [[NSGraphicsContext currentContext] graphicsPort];
dc.context = GET_CGCONTEXT;
dc.portBounds = NSRectToCGRect([view bounds]);
if (dc.clipRgn) {
clipBounds = CGContextGetClipBoundingBox(dc.context);
@@ -1503,14 +1567,17 @@ TkMacOSXSetupDrawingContext(
Tcl_Panic("TkMacOSXSetupDrawingContext(): "
"no context to draw into !");
}
/*
* Configure the drawing context.
*/
if (dc.context) {
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;
if (!dc.focusLocked) {
CGContextSaveGState(dc.context);
}
CGContextSaveGState(dc.context);
CGContextSetTextDrawingMode(dc.context, kCGTextFill);
CGContextConcatCTM(dc.context, t);
if (dc.clipRgn) {
@@ -1545,7 +1612,7 @@ TkMacOSXSetupDrawingContext(
double w = gc->line_width;
TkMacOSXSetColorInContext(gc, gc->foreground, dc.context);
if (isWin) {
if (win) {
CGContextSetPatternPhase(dc.context, CGSizeMake(
dc.portBounds.size.width, dc.portBounds.size.height));
}
@@ -1583,13 +1650,21 @@ TkMacOSXSetupDrawingContext(
}
}
}
end:
if (dontDraw && dc.clipRgn) {
#ifdef TK_MAC_DEBUG_DRAWING
if (!canDraw && win != NULL) {
TkWindow *winPtr = TkMacOSXGetTkWindow(win);
if (winPtr) fprintf(stderr, "Cannot draw in %s - postponing.\n",
Tk_PathName(winPtr));
}
#endif
if (!canDraw && dc.clipRgn) {
CFRelease(dc.clipRgn);
dc.clipRgn = NULL;
}
*dcPtr = dc;
return !dontDraw;
return canDraw;
}
/*
@@ -1614,13 +1689,7 @@ TkMacOSXRestoreDrawingContext(
{
if (dcPtr->context) {
CGContextSynchronize(dcPtr->context);
[[dcPtr->view window] setViewsNeedDisplay:YES];
[[dcPtr->view window] enableFlushWindow];
if (dcPtr->focusLocked) {
[dcPtr->view unlockFocus];
} else {
CGContextRestoreGState(dcPtr->context);
}
CGContextRestoreGState(dcPtr->context);
}
if (dcPtr->clipRgn) {
CFRelease(dcPtr->clipRgn);
@@ -1659,17 +1728,13 @@ TkMacOSXGetClipRgn(
#ifdef TK_MAC_DEBUG_DRAWING
TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName);
NSView *view = TkMacOSXDrawableView(macDraw);
if ([view lockFocusIfCanDraw]) {
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
-1.0, 0.0, [view bounds].size.height));
ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
CGContextEOFillPath(context);
CGContextRestoreGState(context);
[view unlockFocus];
}
CGContextSaveGState(context);
CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
-1.0, 0.0, [view bounds].size.height));
ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
CGContextEOFillPath(context);
CGContextRestoreGState(context);
#endif /* TK_MAC_DEBUG_DRAWING */
}
@@ -1729,13 +1794,11 @@ TkpClipDrawableToRect(
int width, int height)
{
MacDrawable *macDraw = (MacDrawable *) d;
NSView *view = TkMacOSXDrawableView(macDraw);
if (macDraw->drawRgn) {
CFRelease(macDraw->drawRgn);
macDraw->drawRgn = NULL;
}
if (width >= 0 && height >= 0) {
CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
width, height);
@@ -1751,17 +1814,6 @@ TkpClipDrawableToRect(
} else {
macDraw->drawRgn = drawRgn;
}
if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) {
clipRect.origin.y = [view bounds].size.height -
(clipRect.origin.y + clipRect.size.height);
NSRectClip(NSRectFromCGRect(clipRect));
macDraw->flags |= TK_FOCUSED_VIEW;
}
} else {
if (view && (macDraw->flags & TK_FOCUSED_VIEW)) {
[view unlockFocus];
macDraw->flags &= ~TK_FOCUSED_VIEW;
}
}
}