summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Walzer <kw@codebykevin.com>2015-11-07 18:41:19 (GMT)
committerKevin Walzer <kw@codebykevin.com>2015-11-07 18:41:19 (GMT)
commite0a9544076a1f3f079fdd4143ad1214a4cfc4729 (patch)
tree70d0b9cfb4a31fdfeaab0e080f544ace9352c31c
parentabbec4b67a98b0511d851db9fdaf10e9806c8fce (diff)
downloadtk-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.c90
-rw-r--r--macosx/tkMacOSXMouseEvent.c58
-rw-r--r--macosx/tkMacOSXPrivate.h1
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)