diff options
author | Kevin Walzer <kw@codebykevin.com> | 2014-07-24 02:30:25 (GMT) |
---|---|---|
committer | Kevin Walzer <kw@codebykevin.com> | 2014-07-24 02:30:25 (GMT) |
commit | c14530201df3f512c68f49728a3b8fcd2755bfcc (patch) | |
tree | d1885a3da1b2008efb5acfb893efd85c995688f6 /macosx | |
parent | 5a7df0cabf3670fae0c85b2cf48b5455b6aaa054 (diff) | |
download | tk-c14530201df3f512c68f49728a3b8fcd2755bfcc.zip tk-c14530201df3f512c68f49728a3b8fcd2755bfcc.tar.gz tk-c14530201df3f512c68f49728a3b8fcd2755bfcc.tar.bz2 |
Fix for display of images when scrolling a text widget on OS X; thanks to Marc Culler for patch
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/tkMacOSXDraw.c | 116 | ||||
-rw-r--r-- | macosx/tkMacOSXRegion.c | 64 |
2 files changed, 116 insertions, 64 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 167277f..701112d 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -218,8 +218,6 @@ XCopyArea( display->request++; - TkMacOSXDbgMsg("XCopyArea"); - if (!width || !height) { /* This happens all the time. TkMacOSXDbgMsg("Drawing of empty area requested"); @@ -240,7 +238,7 @@ XCopyArea( img = [bitmap_rep CGImage]; } } else { - TkMacOSXDbgMsg("Invalid source drawable"); + TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap."); } if (img) { @@ -250,11 +248,11 @@ XCopyArea( CGRectMake(dest_x, dest_y, width, height)); CFRelease(img); } else { - TkMacOSXDbgMsg("Invalid source drawable"); + TkMacOSXDbgMsg("Failed to construct CGImage."); } } else { - TkMacOSXDbgMsg("Invalid destination drawable"); + TkMacOSXDbgMsg("Invalid destination drawable - no context."); return; } @@ -1480,43 +1478,97 @@ TkScrollWindow( int dx, int dy, /* Distance rectangle should be moved. */ TkRegion damageRgn) /* Region to accumulate damage in. */ { - MacDrawable *macDraw = (MacDrawable *) Tk_WindowId(tkwin); + Drawable drawable = Tk_WindowId(tkwin); + MacDrawable *macDraw = (MacDrawable *) drawable; NSView *view = TkMacOSXDrawableView(macDraw); - CGRect visRect, srcRect, dstRect; - CGFloat boundsH; - HIShapeRef dmgRgn, dstRgn; + CGRect visRect, srcRect, dstRect, scroll_src, scroll_dst; + HIShapeRef dmgRgn = NULL; + NSRect bounds; int result; - if (view && !CGRectIsEmpty(visRect = NSRectToCGRect([view visibleRect]))) { - boundsH = [view bounds].size.height; - srcRect = CGRectMake(macDraw->xOff + x, boundsH - height - - (macDraw->yOff + y), width, height); - dstRect = CGRectIntersection(CGRectOffset(srcRect, dx, -dy), visRect); - srcRect = CGRectIntersection(srcRect, visRect); - if (!CGRectIsEmpty(srcRect) && !CGRectIsEmpty(dstRect)) { + if ( view ) { + /* Get the scroll area in NSView coordinates (origin at bottom left). */ + bounds = [view bounds]; + scroll_src = CGRectMake( + macDraw->xOff + x, + bounds.size.height - height - (macDraw->yOff + y), + width, height); + scroll_dst = CGRectOffset(scroll_src, dx, -dy); + /* Limit scrolling to the window content area. */ + visRect = NSRectToCGRect([view visibleRect]); + scroll_src = CGRectIntersection(scroll_src, visRect); + scroll_dst = CGRectIntersection(scroll_dst, visRect); + + if ( !CGRectIsEmpty(scroll_src) && !CGRectIsEmpty(scroll_dst) ) { + /* - CGRect sRect = CGRectIntersection(CGRectOffset(dstRect, -dx, dy), - srcRect); - NSCopyBits(0, NSRectFromCGRect(sRect), - NSPointFromCGPoint(CGRectOffset(sRect, dx, -dy).origin)); - */ - [view scrollRect:NSRectFromCGRect(srcRect) by:NSMakeSize(dx, -dy)]; + * Mark the difference between source and destination as damaged. + * This region is described in the Tk coordinate system, after shifting by dy. + */ + + srcRect = CGRectMake(x - macDraw->xOff, y - macDraw->yOff, + width, height); + dstRect = CGRectOffset(srcRect, dx, dy); + dmgRgn = HIShapeCreateMutableWithRect(&srcRect); + HIShapeRef dstRgn = HIShapeCreateWithRect(&dstRect); + ChkErr(HIShapeDifference, dmgRgn, dstRgn, (HIMutableShapeRef) dmgRgn); + CFRelease(dstRgn); + + /* Scroll the rectangle. */ + [view scrollRect:NSRectFromCGRect(scroll_src) by:NSMakeSize(dx, -dy)]; + [view displayRect:NSRectFromCGRect(scroll_dst)]; + + /* + * When a Text widget contains embedded images, scrolling generates + * lots of artifacts involving multiple copies of the images + * displayed on top of each other. Extensive experimentation, with + * very little help from the Apple documentation, indicates that + * whenever an image is displayed it gets added as a subview, which + * then gets automatically redisplayed in its original location. + * + * We do two things to combat this. First, each subview that meets + * the scroll area is added as a damage rectangle. Second, we + * redisplay the subviews after the scroll. + */ + + /* + * Step 1: Find any subviews that meet the scroll area and mark + * them as damaged. Use Tk coordinates, shifted to account for the + * future scrolling. + */ + + for (NSView *subview in [view subviews] ) { + NSRect frame = [subview frame]; + CGRect subviewRect = CGRectMake( + frame.origin.x - macDraw->xOff + dx, + (bounds.size.height - frame.origin.y - frame.size.height) - macDraw->yOff + dy, + frame.size.width, frame.size.height); + /* Rectangles with negative coordinates seem to cause trouble. */ + if (subviewRect.origin.y < 0 && subviewRect.origin.y + subviewRect.size.height > 0) { + subviewRect.origin.y = 0; + } + CGRect intersection = CGRectIntersection(srcRect, subviewRect); + if (! CGRectIsEmpty(intersection) ){ + dstRgn = HIShapeCreateWithRect(&subviewRect); + ChkErr(HIShapeUnion, dmgRgn, dstRgn, (HIMutableShapeRef) dmgRgn); + CFRelease(dstRgn); + } + } + + /* Step 2: Redisplay all subviews */ + for (NSView *subview in [view subviews] ) { + [subview display]; + } } - srcRect.origin.y = boundsH - srcRect.size.height - srcRect.origin.y; - dstRect.origin.y = boundsH - dstRect.size.height - dstRect.origin.y; - srcRect = CGRectUnion(srcRect, dstRect); - dmgRgn = HIShapeCreateMutableWithRect(&srcRect); - dstRgn = HIShapeCreateWithRect(&dstRect); - ChkErr(HIShapeDifference, dmgRgn, dstRgn, (HIMutableShapeRef) dmgRgn); - CFRelease(dstRgn); - TkMacOSXInvalidateViewRegion(view, dmgRgn); - } else { + } + + if ( dmgRgn == NULL ) { dmgRgn = HIShapeCreateEmpty(); } + //TkMacOSXInvalidateViewRegion(view, dmgRgn); TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; CFRelease(dmgRgn); - return result; } diff --git a/macosx/tkMacOSXRegion.c b/macosx/tkMacOSXRegion.c index 8432299..c716ab7 100644 --- a/macosx/tkMacOSXRegion.c +++ b/macosx/tkMacOSXRegion.c @@ -158,6 +158,29 @@ TkUnionRectWithRegion( /* *---------------------------------------------------------------------- * + * TkMacOSXIsEmptyRegion -- + * + * Return native region for given tk region. + * + * Results: + * 1 if empty, 0 otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkMacOSXIsEmptyRegion( + TkRegion r) +{ + return HIShapeIsEmpty((HIMutableShapeRef) r) ? 1 : 0; +} + +/* + *---------------------------------------------------------------------- + * * TkRectInRegion -- * * Implements the equivelent of the X window function XRectInRegion. See @@ -181,12 +204,14 @@ TkRectInRegion( unsigned int width, unsigned int height) { - int result; - const CGRect r = CGRectMake(x, y, width, height); - - result = HIShapeIntersectsRect((HIShapeRef) region, &r) ? + if ( TkMacOSXIsEmptyRegion(region) ) { + return RectangleOut; + } + else { + const CGRect r = CGRectMake(x, y, width, height); + return HIShapeIntersectsRect((HIShapeRef) region, &r) ? RectanglePart : RectangleOut; - return result; + } } /* @@ -332,12 +357,11 @@ TkpReleaseRegion( { CFRelease(r); } -#if 0 /* *---------------------------------------------------------------------- * - * TkMacOSXEmtpyRegion -- + * TkMacOSXSetEmptyRegion -- * * Set region to emtpy. * @@ -351,7 +375,7 @@ TkpReleaseRegion( */ void -TkMacOSXEmtpyRegion( +TkMacOSXSetEmptyRegion( TkRegion r) { ChkErr(HIShapeSetEmpty, (HIMutableShapeRef) r); @@ -360,30 +384,6 @@ TkMacOSXEmtpyRegion( /* *---------------------------------------------------------------------- * - * TkMacOSXIsEmptyRegion -- - * - * Return native region for given tk region. - * - * Results: - * 1 if empty, 0 otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkMacOSXIsEmptyRegion( - TkRegion r) -{ - return HIShapeIsEmpty((HIMutableShapeRef) r) ? 1 : 0; -} -#endif - -/* - *---------------------------------------------------------------------- - * * TkMacOSXGetNativeRegion -- * * Return native region for given tk region. |