Index: macosx/tkMacOSXDraw.c ================================================================== --- macosx/tkMacOSXDraw.c +++ macosx/tkMacOSXDraw.c @@ -1612,40 +1612,47 @@ if (dc.context) { dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context); } else if (win) { NSView *view = TkMacOSXDrawableView(macDraw); + /* + * We can only draw into the view when the current CGContext is + * valid. Starting with OSX 10.14, 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 then we mark our view as needing + * display in the bounding rectangle of the clipping region and + * return failure. That rectangle should get drawn in a later call + * to drawRect. + */ + if (!view) { Tcl_Panic("TkMacOSXSetupDrawingContext(): " "no NSView to draw into !"); } - - /* - * 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]; + if (![NSApp isDrawing]) { + NSRect bounds = [view bounds]; + NSRect dirtyNS = bounds; + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, + .ty = dirtyNS.size.height}; + if (dc.clipRgn) { + CGRect dirtyCG = NSRectToCGRect(dirtyNS); + HIShapeGetBounds(dc.clipRgn, &dirtyCG); + dirtyNS = NSRectToCGRect(CGRectApplyAffineTransform(dirtyCG, t)); + } + [view setNeedsDisplayInRect:dirtyNS]; canDraw = false; goto end; } dc.view = view; dc.context = GET_CGCONTEXT; dc.portBounds = NSRectToCGRect([view bounds]); if (dc.clipRgn) { clipBounds = CGContextGetClipBoundingBox(dc.context); } - } else { - Tcl_Panic("TkMacOSXSetupDrawingContext(): " - "no context to draw into !"); } /* * Configure the drawing context. */ Index: macosx/tkMacOSXWindowEvent.c ================================================================== --- macosx/tkMacOSXWindowEvent.c +++ macosx/tkMacOSXWindowEvent.c @@ -427,10 +427,17 @@ CFRelease(boundsRgn); return 0; } HIShapeGetBounds(damageRgn, &damageBounds); + /* + * Expand the damage rectangle a bit to avoid artifacts when + * moving canvas items very quickly. + */ + + damageBounds = CGRectInset(damageBounds, -10, -10); + CFRelease(damageRgn); CFRelease(boundsRgn); event.xany.serial = LastKnownRequestProcessed(Tk_Display(winPtr)); event.xany.send_event = false; @@ -452,26 +459,26 @@ /* * Generate updates for the children of this window */ for (childPtr = winPtr->childList; childPtr != NULL; - childPtr = childPtr->nextPtr) { - if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { - continue; - } - GenerateUpdates(updateRgn, updateBounds, childPtr); + childPtr = childPtr->nextPtr) { + if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { + continue; + } + GenerateUpdates(updateRgn, updateBounds, childPtr); } /* * Generate updates for any contained windows */ if (Tk_IsContainer(winPtr)) { - childPtr = TkpGetOtherWindow(winPtr); - if (childPtr != NULL && Tk_IsMapped(childPtr)) { - GenerateUpdates(updateRgn, updateBounds, childPtr); - } + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL && Tk_IsMapped(childPtr)) { + GenerateUpdates(updateRgn, updateBounds, childPtr); + } /* * TODO: Here we should handle out of process embedding. */ }