diff options
author | Kevin Walzer <kw@codebykevin.com> | 2015-11-07 18:41:19 (GMT) |
---|---|---|
committer | Kevin Walzer <kw@codebykevin.com> | 2015-11-07 18:41:19 (GMT) |
commit | e0a9544076a1f3f079fdd4143ad1214a4cfc4729 (patch) | |
tree | 70d0b9cfb4a31fdfeaab0e080f544ace9352c31c | |
parent | abbec4b67a98b0511d851db9fdaf10e9806c8fce (diff) | |
download | tk-e0a9544076a1f3f079fdd4143ad1214a4cfc4729.zip tk-e0a9544076a1f3f079fdd4143ad1214a4cfc4729.tar.gz tk-e0a9544076a1f3f079fdd4143ad1214a4cfc4729.tar.bz2 |
Fix for issues with bitmap rendering and mouse events in Tk-Cocoa; thanks to Marc Culler for patches
-rw-r--r-- | macosx/tkMacOSXDraw.c | 90 | ||||
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 58 | ||||
-rw-r--r-- | macosx/tkMacOSXPrivate.h | 1 |
3 files changed, 94 insertions, 55 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 5f31a2c..185d65a 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -141,7 +141,7 @@ BitmapRepFromDrawableRect( if ( mac_drawable->flags & TK_IS_PIXMAP ) { /* This means that the MacDrawable is functioning as a Tk Pixmap, so its view - field is NULL. It's context field should point to a CGImage. + field is NULL. */ cg_context = GetCGContextForDrawable(drawable); CGRect image_rect = CGRectMake(x, y, width, height); @@ -199,10 +199,10 @@ XCopyArea( Display *display, /* Display. */ Drawable src, /* Source drawable. */ Drawable dst, /* Destination drawable. */ - GC gc, /* GC to use. */ + 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 width, /* that will be copied. */ unsigned int height, int dest_x, /* Dest X & Y on dest rect. */ int dest_y) @@ -282,10 +282,10 @@ XCopyPlane( Display *display, /* Display. */ Drawable src, /* Source drawable. */ Drawable dst, /* Destination drawable. */ - GC gc, /* GC to use. */ + 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 width, /* that will be copied. */ unsigned int height, int dest_x, /* Dest X & Y on dest rect. */ int dest_y, @@ -293,6 +293,7 @@ XCopyPlane( { TkMacOSXDrawingContext dc; MacDrawable *srcDraw = (MacDrawable *) src; + MacDrawable *dstDraw = (MacDrawable *) dst; display->request++; if (!width || !height) { @@ -306,33 +307,47 @@ XCopyPlane( if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { return; } - if (dc.context) { + 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 && - clipPtr->value.pixmap == src) { - imageBackground = TRANSPARENT_PIXEL << 24; + if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){ + CGImageRef mask = TkMacOSXCreateCGImageWithDrawable(clipPtr->value.pixmap); + 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, mask); + TkMacOSXSetColorInContext(gc, gc->background, dc.context); + CGContextFillRect(dc.context, rect); + /* Fill with the foreground color, clipping to the intersection of img and mask. */ + CGContextClipToMask(context, rect, img); + TkMacOSXSetColorInContext(gc, gc->foreground, context); + CGContextFillRect(context, rect); + CGContextRestoreGState(context); + CGImageRelease(mask); + CGImageRelease(img); + } else { + DrawCGImage(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)); + CGImageRelease(img); } - DrawCGImage(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)); - CFRelease(img); - } else { + } else { /* no image */ TkMacOSXDbgMsg("Invalid source drawable"); } } else { - TkMacOSXDbgMsg("Invalid destination drawable"); + TkMacOSXDbgMsg("Invalid destination drawable - could not get a bitmap context."); } TkMacOSXRestoreDrawingContext(&dc); - } else { - XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, - dest_y); + } else { /* source drawable is a window, not a Pixmap */ + XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y); } } @@ -356,16 +371,16 @@ XCopyPlane( int TkPutImage( unsigned long *colors, /* Unused on Macintosh. */ - int ncolors, /* Unused on Macintosh. */ + int ncolors, /* Unused on Macintosh. */ Display* display, /* Display. */ Drawable d, /* Drawable to place image on. */ - GC gc, /* GC to use. */ + 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 width, /* Same width & height for both */ unsigned int height) /* distination and source. */ { TkMacOSXDrawingContext dc; @@ -431,11 +446,12 @@ CreateCGImageWithXImage( * BW image */ + /* Reverses the sense of the bits */ static const CGFloat decodeWB[2] = {1, 0}; + decode = decodeWB; bitsPerComponent = 1; bitsPerPixel = 1; - decode = decodeWB; if (image->bitmap_bit_order != MSBFirst) { char *srcPtr = image->data + image->xoffset; char *endPtr = srcPtr + len; @@ -445,22 +461,20 @@ CreateCGImageWithXImage( *destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))]; } } else { - data = memcpy(ckalloc(len), image->data + image->xoffset, - len); + data = memcpy(ckalloc(len), image->data + image->xoffset, len); } if (data) { provider = CGDataProviderCreateWithData(data, data, len, releaseData); } if (provider) { img = CGImageMaskCreate(image->width, image->height, bitsPerComponent, - bitsPerPixel, image->bytes_per_line, - provider, decode, 0); + bitsPerPixel, image->bytes_per_line, provider, decode, 0); } } else if (image->format == ZPixmap && image->bits_per_pixel == 32) { /* * Color image */ - + CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); bitsPerComponent = 8; @@ -476,6 +490,7 @@ CreateCGImageWithXImage( img = CGImageCreate(image->width, image->height, bitsPerComponent, bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo, provider, decode, 0, kCGRenderingIntentDefault); + CFRelease(provider); } if (colorspace) { CFRelease(colorspace); @@ -483,10 +498,6 @@ CreateCGImageWithXImage( } else { TkMacOSXDbgMsg("Unsupported image type"); } - if (provider) { - CFRelease(provider); - } - return img; } @@ -660,8 +671,7 @@ GetCGContextForDrawable( kCGBitmapByteOrderDefault; #endif char *data; - CGRect bounds = CGRectMake(0, 0, macDraw->size.width, - macDraw->size.height); + CGRect bounds = CGRectMake(0, 0, macDraw->size.width, macDraw->size.height); if (macDraw->flags & TK_IS_BW_PIXMAP) { bitsPerPixel = 8; @@ -738,6 +748,7 @@ DrawCGImage( 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. */ if (imageBackground != TRANSPARENT_PIXEL << 24) { CGContextClearRect(context, dstBounds); } @@ -750,6 +761,7 @@ DrawCGImage( TkMacOSXSetColorInContext(gc, imageForeground, context); } } + #ifdef TK_MAC_DEBUG_IMAGE_DRAWING CGContextSaveGState(context); CGContextSetLineWidth(context, 1.0); @@ -768,9 +780,9 @@ DrawCGImage( dstBounds.origin.x, dstBounds.origin.y, dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ + CGContextSaveGState(context); - CGContextTranslateCTM(context, 0, - dstBounds.origin.y + CGRectGetMaxY(dstBounds)); + CGContextTranslateCTM(context, 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); CGContextRestoreGState(context); diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 8c0a2e6..31038b5 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -34,6 +34,18 @@ enum { NSWindowWillMoveEventType = 20 }; +/* + * In OS X 10.6 an NSEvent of type NSMouseMoved would always have a non-Nil + * window attribute when the mouse was inside a window. As of 10.8 this + * behavior had changed. The new behavior was that if the mouse were ever + * moved outside of a window, all subsequent NSMouseMoved NSEvents would have a + * Nil window attribute. To work around this we remember which window the + * mouse is in by saving the window attribute of each NSEvent of type + * NSMouseEntered. If an NSEvent has a Nil window attribute we use our saved + * window. It may be the case that the mouse has actually left the window, but + * this is harmless since Tk will ignore the event in that case. + */ + @implementation TKApplication(TKMouseEvent) - (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent { @@ -49,12 +61,11 @@ enum { switch (type) { case NSMouseEntered: + /* Remember which window has the mouse. */ + _windowWithMouse = [theEvent window]; + break; case NSMouseExited: case NSCursorUpdate: -#if 0 - trackingArea = [theEvent trackingArea]; - /* fall through */ -#endif case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: @@ -65,14 +76,6 @@ enum { case NSRightMouseDragged: case NSOtherMouseDragged: case NSMouseMoved: -#if 0 - eventNumber = [theEvent eventNumber]; - if (!trackingArea) { - clickCount = [theEvent clickCount]; - buttonNumber = [theEvent buttonNumber]; - } - /* fall through */ -#endif case NSTabletPoint: case NSTabletProximity: case NSScrollWheel: @@ -85,13 +88,36 @@ enum { /* Create an Xevent to add to the Tk queue. */ win = [theEvent window]; NSPoint global, local = [theEvent locationInWindow]; - if (win) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + /* convertBaseToScreen and convertScreenToBase were deprecated in 10.7. */ + NSRect pointrect; + pointrect.origin = local; + pointrect.size.width = 0; + pointrect.size.height = 0; +#endif + if (win) { /* local will be in window coordinates. */ +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + global = [win convertRectToScreen:pointrect].origin; +#else global = [win convertBaseToScreen:local]; +#endif local.y = [win frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; - } else { - local.y = tkMacOSXZeroScreenHeight - local.y; - global = local; + } else { /* local will be in screen coordinates. */ + if (_windowWithMouse ) { + win = _windowWithMouse; + global = local; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + local = [win convertRectFromScreen:pointrect].origin; +#else + local = [win convertScreenToBase:local]; +#endif + local.y = [win frame].size.height - local.y; + global.y = tkMacOSXZeroScreenHeight - global.y; + } else { /* We have no window. Use the screen???*/ + local.y = tkMacOSXZeroScreenHeight - local.y; + global = local; + } } Window window = TkMacOSXGetXWindow(win); diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 2de3673..1d20081 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -274,6 +274,7 @@ VISIBILITY_HIDDEN TKMenu *_defaultMainMenu, *_defaultApplicationMenu; NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems; NSArray *_defaultHelpMenuItems; + NSWindow *_windowWithMouse; } @end @interface TKApplication(TKInit) |