summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorculler <culler>2021-04-29 22:09:38 (GMT)
committerculler <culler>2021-04-29 22:09:38 (GMT)
commita723a9e97cc86c5cbee7c26aca2d344ad18c12a1 (patch)
treec94197ad83fef8a461bca50e4da2e16e10ede0fa /macosx
parent0e9151d4eb452e294ed0a40869ad97a7c54eed3d (diff)
parenta3be6c56b7742a8c7f8b8f3c193ae6304e2a2cb2 (diff)
downloadtk-a723a9e97cc86c5cbee7c26aca2d344ad18c12a1.zip
tk-a723a9e97cc86c5cbee7c26aca2d344ad18c12a1.tar.gz
tk-a723a9e97cc86c5cbee7c26aca2d344ad18c12a1.tar.bz2
For Aqua, use an explicit backing CALayer for the TKContentView. Fixes [d281848f97] and other rendering issues.
Diffstat (limited to 'macosx')
-rw-r--r--macosx/tkMacOSXDraw.c56
-rw-r--r--macosx/tkMacOSXFont.c2
-rw-r--r--macosx/tkMacOSXImage.c73
-rw-r--r--macosx/tkMacOSXNotify.c8
-rw-r--r--macosx/tkMacOSXPrivate.h2
-rw-r--r--macosx/tkMacOSXRegion.c2
-rw-r--r--macosx/tkMacOSXWindowEvent.c35
-rw-r--r--macosx/tkMacOSXWm.c19
8 files changed, 134 insertions, 63 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index bf6a4a7..d5396eb 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -27,6 +27,7 @@
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_DRAWING
#define TK_MAC_DEBUG_IMAGE_DRAWING
+#define TK_MAC_DEBUG_CG
#endif
*/
@@ -1265,6 +1266,12 @@ TkMacOSXSetupDrawingContext(
Bool canDraw = true;
TKContentView *view = nil;
TkMacOSXDrawingContext dc = {};
+ CGFloat drawingHeight;
+
+#ifdef TK_MAC_DEBUG_CG
+ fprintf(stderr, "TkMacOSXSetupDrawingContext: %s\n",
+ macDraw->winPtr ? Tk_PathName(macDraw->winPtr) : "None");
+#endif
/*
* If the drawable is not a pixmap, get the associated NSView.
@@ -1296,13 +1303,10 @@ TkMacOSXSetupDrawingContext(
*/
dc.context = TkMacOSXGetCGContextForDrawable(d);
- if (dc.context) {
- dc.portBounds = CGContextGetClipBoundingBox(dc.context);
- } else {
+ if (!dc.context) {
NSRect drawingBounds, currentBounds;
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,
@@ -1354,15 +1358,20 @@ TkMacOSXSetupDrawingContext(
* Finish configuring the drawing context.
*/
+ drawingHeight = view ? [view bounds].size.height :
+ CGContextGetClipBoundingBox(dc.context).size.height;
CGAffineTransform t = {
.a = 1, .b = 0,
.c = 0, .d = -1,
.tx = 0,
- .ty = dc.portBounds.size.height
+ .ty = drawingHeight
};
- dc.portBounds.origin.x += macDraw->xOff;
- dc.portBounds.origin.y += macDraw->yOff;
+#ifdef TK_MAC_DEBUG_CG
+ fprintf(stderr, "TkMacOSXSetupDrawingContext: pushing GState for %s\n",
+ macDraw->winPtr ? Tk_PathName(macDraw->winPtr) : "None");
+#endif
+
CGContextSaveGState(dc.context);
CGContextSetTextDrawingMode(dc.context, kCGTextFill);
CGContextConcatCTM(dc.context, t);
@@ -1388,11 +1397,26 @@ TkMacOSXSetupDrawingContext(
*/
ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
+
+#ifdef TK_MAC_DEBUG_CG
+ fprintf(stderr, "Setting complex clip for %s to:\n",
+ macDraw->winPtr ? Tk_PathName(macDraw->winPtr) : "None");
+ TkMacOSXPrintRectsInRegion(dc.clipRgn);
+#endif
+
CGContextEOClip(dc.context);
- }
- else {
+ } else {
CGRect r;
HIShapeGetBounds(dc.clipRgn, &r);
+
+#ifdef TK_MAC_DEBUG_CG
+ fprintf(stderr, "Current clip BBox is %s\n",
+ NSStringFromRect(CGContextGetClipBoundingBox(GET_CGCONTEXT)).UTF8String);
+ fprintf(stderr, "Setting clip for %s to rect %s:\n",
+ macDraw->winPtr ? Tk_PathName(macDraw->winPtr) : "None",
+ NSStringFromRect(r).UTF8String);
+#endif
+
CGContextClipToRect(dc.context, r);
}
}
@@ -1413,8 +1437,8 @@ TkMacOSXSetupDrawingContext(
TkMacOSXSetColorInContext(gc, gc->foreground, dc.context);
if (view) {
- CGContextSetPatternPhase(dc.context,
- CGSizeMake(dc.portBounds.size.width, dc.portBounds.size.height));
+ CGSize size = NSSizeToCGSize([view bounds].size);
+ CGContextSetPatternPhase(dc.context, size);
}
if (gc->function != GXcopy) {
TkMacOSXDbgMsg("Logical functions other than GXcopy are "
@@ -1491,13 +1515,21 @@ TkMacOSXRestoreDrawingContext(
if (dcPtr->context) {
CGContextSynchronize(dcPtr->context);
CGContextRestoreGState(dcPtr->context);
+
+#ifdef TK_MAC_DEBUG_CG
+ fprintf(stderr, "TkMacOSXRestoreDrawingContext: popped GState\n");
+#endif
+
}
if (dcPtr->clipRgn) {
CFRelease(dcPtr->clipRgn);
+ dcPtr->clipRgn = NULL;
}
+
#ifdef TK_MAC_DEBUG
bzero(dcPtr, sizeof(TkMacOSXDrawingContext));
-#endif /* TK_MAC_DEBUG */
+#endif
+
}
/*
diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c
index feff3bf..d9c1c01 100644
--- a/macosx/tkMacOSXFont.c
+++ b/macosx/tkMacOSXFont.c
@@ -1219,7 +1219,7 @@ TkpDrawAngledCharsInContext(
(CFAttributedStringRef)attributedString);
textX += (CGFloat) macWin->xOff;
textY += (CGFloat) macWin->yOff;
- height = drawingContext.portBounds.size.height;
+ height = [drawingContext.view bounds].size.height;
textY = height - textY;
t = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, height);
if (angle != 0.0) {
diff --git a/macosx/tkMacOSXImage.c b/macosx/tkMacOSXImage.c
index 69967af..de19f2b 100644
--- a/macosx/tkMacOSXImage.c
+++ b/macosx/tkMacOSXImage.c
@@ -528,51 +528,42 @@ CreateCGImageFromDrawableRect(
{
MacDrawable *mac_drawable = (MacDrawable *)drawable;
CGContextRef cg_context = NULL;
+ CGRect image_rect = CGRectMake(x, y, width, height);
CGImageRef cg_image = NULL, result = NULL;
- NSBitmapImageRep *bitmapRep = nil;
- NSView *view = nil;
+ unsigned char *imageData = 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);
- if (cg_image) {
- result = CGImageCreateWithImageInRect(cg_image, image_rect);
- CGImageRelease(cg_image);
- }
- } else if (TkMacOSXGetNSViewForDrawable(mac_drawable) != nil) {
-
- /*
- * 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 just return NULL.
- */
-
- if (view == [NSView focusView]) {
- bitmapRep = [view bitmapImageRepForCachingDisplayInRect: view_rect];
- [view cacheDisplayInRect:view_rect toBitmapImageRep:bitmapRep];
- result = [bitmapRep CGImage];
- CFRelease(bitmapRep);
- } else {
- TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap.");
- result = NULL;
+ if (cg_context) {
+ cg_image = CGBitmapContextCreateImage((CGContextRef) cg_context);
}
} else {
- TkMacOSXDbgMsg("Invalid source drawable");
+ NSView *view = TkMacOSXGetNSViewForDrawable(mac_drawable);
+ if (view == nil) {
+ TkMacOSXDbgMsg("Invalid source drawable");
+ return NULL;
+ }
+ NSSize size = view.frame.size;
+ NSUInteger width = size.width, height = size.height;
+ NSUInteger bytesPerPixel = 4,
+ bytesPerRow = bytesPerPixel * width,
+ bitsPerComponent = 8;
+ imageData = ckalloc(height * bytesPerRow);
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ cg_context = CGBitmapContextCreate(imageData, width, height,
+ bitsPerComponent, bytesPerRow, colorSpace,
+ kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+ CFRelease(colorSpace);
+ [view.layer renderInContext:cg_context];
+ }
+ if (cg_context) {
+ cg_image = CGBitmapContextCreateImage(cg_context);
+ CGContextRelease(cg_context);
+ }
+ if (cg_image) {
+ result = CGImageCreateWithImageInRect(cg_image, image_rect);
+ CGImageRelease(cg_image);
}
+ ckfree(imageData);
return result;
}
@@ -676,11 +667,11 @@ XGetImage(
|| bytes_per_row < 4 * width
|| size != bytes_per_row * height) {
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
- CFRelease(bitmapRep);
+ [bitmapRep release];
return NULL;
}
memcpy(bitmap, (char *)[bitmapRep bitmapData], size);
- CFRelease(bitmapRep);
+ [bitmapRep release];
/*
* When Apple extracts a bitmap from an NSView, it may be in either
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index f32fa76..208d846 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -340,8 +340,9 @@ TkMacOSXNotifyExitHandler(
* for all views that need display before it returns. We call it with
* deQueue=NO so that it will not change anything on the AppKit event
* queue, because we only want the side effect that it runs drawRect. The
- * only time when any NSViews have the needsDisplay property set to YES
- * is during execution of this function.
+ * only times when any NSViews have the needsDisplay property set to YES
+ * are during execution of this function or in the addDirtyRect method
+ * of TKContentView.
*
* The reason for running this function as an idle task is to try to
* arrange that all widgets will be fully configured before they are
@@ -377,7 +378,8 @@ TkMacOSXDrawAllViews(
if (dirtyCount) {
continue;
}
- [view setNeedsDisplayInRect:[view tkDirtyRect]];
+ [[view layer] setNeedsDisplayInRect:[view tkDirtyRect]];
+ [view setNeedsDisplay:YES];
}
} else {
[window displayIfNeeded];
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index 0bd46c6..be2264f 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -27,6 +27,7 @@
#define TextStyle MacTextStyle
#import <ApplicationServices/ApplicationServices.h>
#import <Cocoa/Cocoa.h>
+#import <QuartzCore/QuartzCore.h>
#ifndef NO_CARBON_H
#import <Carbon/Carbon.h>
#endif
@@ -203,7 +204,6 @@ typedef struct TkMacOSXDrawingContext {
CGContextRef context;
NSView *view;
HIShapeRef clipRgn;
- CGRect portBounds;
} TkMacOSXDrawingContext;
/*
diff --git a/macosx/tkMacOSXRegion.c b/macosx/tkMacOSXRegion.c
index 3c168f1..fbb41cb 100644
--- a/macosx/tkMacOSXRegion.c
+++ b/macosx/tkMacOSXRegion.c
@@ -575,7 +575,7 @@ rectPrinter(
void *ref)
{
if (rect) {
- printf(" %s\n", NSStringFromRect(*rect).UTF8String);
+ fprintf(stderr, " %s\n", NSStringFromRect(*rect).UTF8String);
}
return noErr;
}
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 0075fb8..f7a160a 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -915,11 +915,46 @@ ConfigureRestrictProc(
@implementation TKContentView(TKWindowEvent)
+- (id)initWithFrame:(NSRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self) {
+ /*
+ * The layer must exist before we set wantsLayer to YES.
+ */
+
+ self.layer = [CALayer layer];
+ self.wantsLayer = YES;
+ self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
+ self.layer.contentsGravity = self.layer.contentsAreFlipped ?
+ kCAGravityTopLeft : kCAGravityBottomLeft;
+
+ /*
+ * Nothing gets drawn at all if the layer does not have a delegate.
+ * Currently, we do not implement any methods of the delegate, however.
+ */
+
+ self.layer.delegate = (id) self;
+ }
+ return self;
+}
+
+/*
+ * We will just use drawRect.
+ */
+
+- (BOOL) wantsUpdateLayer
+{
+ return NO;
+}
+
- (void) addTkDirtyRect: (NSRect) rect
{
_tkNeedsDisplay = YES;
_tkDirtyRect = NSUnionRect(_tkDirtyRect, rect);
[NSApp setNeedsToDraw:YES];
+ [self setNeedsDisplay:YES];
+ [[self layer] setNeedsDisplay];
}
- (void) clearTkDirtyRect
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 4f073d8..e039072 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -5535,12 +5535,15 @@ Tk_MacOSXGetTkWindow(
void *w)
{
Window window = None;
- TkDisplay *dispPtr = TkGetDisplayList();
if ([(NSWindow *)w respondsToSelector: @selector (tkWindow)]) {
window = [(TKWindow *)w tkWindow];
}
- return (window != None ?
- Tk_IdToWindow(dispPtr->display, window) : NULL);
+ if (window) {
+ TkDisplay *dispPtr = TkGetDisplayList();
+ return Tk_IdToWindow(dispPtr->display, window);
+ } else {
+ return NULL;
+ }
}
/*
@@ -6271,6 +6274,7 @@ TkMacOSXMakeRealWindowExist(
Tk_ChangeWindowAttributes((Tk_Window)winPtr, CWOverrideRedirect, &atts);
ApplyContainerOverrideChanges(winPtr, NULL);
}
+ [window display];
}
/*
@@ -6442,6 +6446,12 @@ TkpWmSetState(
macWin = TkMacOSXGetNSWindowForDrawable(winPtr->window);
+ /*
+ * Make sure windows are updated before the state change.
+ */
+
+ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {};
+
if (state == WithdrawnState) {
Tk_UnmapWindow((Tk_Window)winPtr);
} else if (state == IconicState) {
@@ -6462,8 +6472,9 @@ TkpWmSetState(
[macWin orderFront:NSApp];
TkMacOSXZoomToplevel(macWin, state == NormalState ? inZoomIn : inZoomOut);
}
+
/*
- * Make sure windows are updated after the state change.
+ * Make sure windows are updated after the state change too.
*/
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)){}