diff options
-rw-r--r-- | generic/tkFont.c | 2 | ||||
-rw-r--r-- | macosx/tkMacOSXDraw.c | 55 | ||||
-rw-r--r-- | macosx/tkMacOSXNotify.c | 68 | ||||
-rw-r--r-- | macosx/tkMacOSXPrivate.h | 1 | ||||
-rw-r--r-- | macosx/tkMacOSXWindowEvent.c | 40 | ||||
-rw-r--r-- | tests/canvImg.test | 8 | ||||
-rw-r--r-- | tests/image.test | 17 | ||||
-rw-r--r-- | tests/listbox.test | 4 |
8 files changed, 90 insertions, 105 deletions
diff --git a/generic/tkFont.c b/generic/tkFont.c index e53e3f9..17e0aa9 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -880,7 +880,7 @@ TheWorldHasChanged( * This is ignored on other platforms. */ - if (!TkpWillDrawWidget(NULL)) { + if (TkpWillDrawWidget(NULL)) { return; } diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index dcc3d79..1ec2cfe 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -1631,30 +1631,47 @@ TkMacOSXSetupDrawingContext( Tcl_Panic("TkMacOSXSetupDrawingContext(): " "no NSView to draw into !"); } + if (dc.clipRgn) { + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, + .ty = [view bounds].size.height}; + HIShapeGetBounds(dc.clipRgn, &clipBounds); + clipBounds = CGRectApplyAffineTransform(clipBounds, t); + } + if (![NSApp isDrawing] || view != [NSView focusView]) { - /* - * 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 then we mark our view as needing - * display. We could try to optimize by computing a smaller dirty rect - * here. - */ + /* + * 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 then we mark our view as + * needing display. + */ - if (![NSApp isDrawing] || view != [NSView focusView]) { - NSRect dirtyRect = [view bounds]; if (dc.clipRgn) { - CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, - .ty = dirtyRect.size.height}; - HIShapeGetBounds(dc.clipRgn, &clipBounds); - clipBounds = CGRectApplyAffineTransform(clipBounds, t); - dirtyRect = NSRectFromCGRect(clipBounds); + [view addTkDirtyRect:clipBounds]; + } else { + [view addTkDirtyRect:[view bounds]]; } - [view addTkDirtyRect:dirtyRect]; canDraw = false; goto end; + } else if (dc.clipRgn) { + + /* + * Drawing can also fail when we are being called from drawRect but + * the clipping region set by drawRect does not contain the clipping + * region of our drawing context. See bug [2a61eca3a8]. + */ + + CGRect currentClip = CGContextGetClipBoundingBox( + [NSGraphicsContext currentContext].CGContext); + if (!NSContainsRect(currentClip, clipBounds)) { + [view addTkDirtyRect:clipBounds]; + // XXXX we should be able to skip drawing but sometimes the clipBounds + // are wrong. + //canDraw = false; + //goto end; + } } dc.view = view; @@ -1686,6 +1703,7 @@ TkMacOSXSetupDrawingContext( CGContextSetTextDrawingMode(dc.context, kCGTextFill); CGContextConcatCTM(dc.context, t); if (dc.clipRgn) { + #ifdef TK_MAC_DEBUG_DRAWING CGContextSaveGState(dc.context); ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context); @@ -1693,6 +1711,7 @@ TkMacOSXSetupDrawingContext( CGContextEOFillPath(dc.context); CGContextRestoreGState(dc.context); #endif /* TK_MAC_DEBUG_DRAWING */ + CGRect r; if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect( diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index f8ac50d..7de6bec 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -307,19 +307,20 @@ TkMacOSXNotifyExitHandler( * is undocumented, namely that it sometimes blocks and calls drawRect * 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. This function is the only place where NSViews get the - * needsDisplay property set to YES. + * 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. * - * The reason for running this as an idle task is to try to arrange that - * all widgets will be fully configured before they are drawn. Any idle - * tasks that might reconfigure them should be higher on the idle queue, - * so they should be run before the display procs are run by drawRect. + * 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 + * drawn. Any idle tasks that might reconfigure them should be higher on + * the idle queue, so they should be run before the display procs are run + * by drawRect. * - * If this is called directly with non-NULL clientData parameter then the - * int which it references will be set to the number of windows that need - * display, but the needsDisplay property of those windows will not be - * changed. + * If this function is called directly with non-NULL clientData parameter + * then the int which it references will be set to the number of windows + * that need display, but the needsDisplay property of those windows will + * not be changed. * * Results: * None. @@ -330,11 +331,11 @@ TkMacOSXNotifyExitHandler( *---------------------------------------------------------------------- */ -static void +void TkMacOSXDrawAllViews( ClientData clientData) { - int count = 0, *dirtyCount = (int *)clientData; + int count = 0, *dirtyCount = (int *)clientData; for (NSWindow *window in [NSApp windows]) { if ([[window contentView] isMemberOfClass:[TKContentView class]]) { @@ -342,22 +343,37 @@ TkMacOSXDrawAllViews( if ([view tkNeedsDisplay]) { count++; if (dirtyCount) { - continue; + continue; } [view setNeedsDisplayInRect:[view tkDirtyRect]]; + [view setTkDirtyRect:NSZeroRect]; } } else { [window displayIfNeeded]; } } if (dirtyCount) { - *dirtyCount = count; + *dirtyCount = count; } - [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:NO]; + for (NSWindow *window in [NSApp windows]) { + if ([[window contentView] isMemberOfClass:[TKContentView class]]) { + TKContentView *view = [window contentView]; + + /* + * If we did not run drawRect, we set needsDisplay back to NO. + * Note that if drawRect did run it may have added to Tk's dirty + * rect, due to attempts to draw outside of drawRect's dirty rect. + */ + + if ([view tkNeedsDisplay]) { + [view setNeedsDisplay: NO]; + } + } + } } /* @@ -399,10 +415,11 @@ TkMacOSXEventsSetupProc( [NSApp _resetAutoreleasePool]; /* - * Call this with dequeue=NO to see if there are any events. If so, - * we set the block time to 0 and stop the heartbeat. Tcl_DoOneEvent - * will call the check proc to collect the events and translate them - * into XEvents. But also, drawRect may run. + * Call this with dequeue=NO to see if there are any events. If so, we + * set the block time to 0 and stop the heartbeat. Next Tcl_DoOneEvent + * will call Tcl_WaitForEvent, which will poll instead of waiting since + * the block time is 0. Then it will call check proc to collect the + * events and translate them into XEvents. */ NSEvent *currentEvent = @@ -428,11 +445,7 @@ TkMacOSXEventsSetupProc( havePeriodicEvents = YES; [NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.1]; } - - /* - * Without this, new windows are sometimes not completely rendered. - */ - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}; TkMacOSXDrawAllViews(NULL); } } @@ -521,7 +534,6 @@ TkMacOSXEventsCheckProc( } } } else { - break; } } while (1); @@ -529,8 +541,8 @@ TkMacOSXEventsCheckProc( /* * Now we can unlock the pool. */ - [NSApp _unlockAutoreleasePool]; + [NSApp _unlockAutoreleasePool]; if (eventsFound == 0) { /* @@ -552,7 +564,7 @@ TkMacOSXEventsCheckProc( if (dirtyCount > 0) { Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL); Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); - } + } } } } diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 11dee7c..719b0b1 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -309,6 +309,7 @@ MODULE_SCOPE int TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData, MODULE_SCOPE unsigned TkMacOSXAddVirtual(unsigned int keycode); MODULE_SCOPE void TkMacOSXWinNSBounds(TkWindow *winPtr, NSView *view, NSRect *bounds); +MODULE_SCOPE void TkMacOSXDrawAllViews(ClientData clientData); #pragma mark Private Objective-C Classes diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 6c7e9ff..0f58c70 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -122,7 +122,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; */ while (Tcl_ServiceEvent(0)) {} - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {} /* * NSWindowDidDeminiaturizeNotification is received after @@ -919,32 +919,6 @@ ConfigureRestrictProc( return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } -/* - * If a window gets mapped inside the drawRect method, this will be run as an - * idle task, after drawRect returns, to clean up the mess. - */ - -static void -RedisplayView( - ClientData clientdata) -{ - TKContentView *view = (TKContentView *) clientdata; - - /* - * Make sure that we are not trying to displaying a view that no longer - * exists. Must call [NSApp windows] because [NSApp orderedWindows] excludes - * floating/utility windows and other window panels. - */ - - for (NSWindow *w in [NSApp windows]) { - if ([w contentView] == view) { - [view setTkNeedsDisplay:YES]; - [view setTkDirtyRect:[view bounds]]; - break; - } - } -} - @implementation TKContentView(TKWindowEvent) - (void) addTkDirtyRect: (NSRect) rect @@ -983,21 +957,16 @@ RedisplayView( } [NSApp setIsDrawing: YES]; - -#ifdef TK_MAC_DEBUG_DRAWING - fprintf(stderr, "drawRect: %s\n", NSStringFromRect(rect).UTF8String; -#endif - + [self setTkDirtyRect:NSZeroRect]; [self generateExposeEvents:rect]; + [self setTkNeedsDisplay: NO]; [NSApp setIsDrawing: NO]; if ([self needsRedisplay]) { [self setNeedsRedisplay:NO]; - Tcl_DoWhenIdle(RedisplayView, self); + Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL); } - [self clearTkDirtyRect]; - #ifdef TK_MAC_DEBUG_DRAWING fprintf(stderr, "drawRect: done.\n"); #endif @@ -1102,6 +1071,7 @@ RedisplayView( /* * First process all of the Expose events. */ + while (Tcl_ServiceEvent(TCL_IDLE_EVENTS)) {}; oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {}; diff --git a/tests/canvImg.test b/tests/canvImg.test index b60e384..1abea78 100644 --- a/tests/canvImg.test +++ b/tests/canvImg.test @@ -727,12 +727,6 @@ test canvImg-9.1 {DisplayImage procedure} -constraints testImageType -setup { image delete foo } -result {75 150 105 165} -if {[tk windowingsystem] == "aqua" && $tcl_platform(osVersion) > 18} { - # Aqua >= 10.14 will redraw the entire image. - set result_10_1 {{foo display 0 0 30 15}} -} else { - set result_10_1 {{foo display 2 4 6 8}} -} test canvImg-10.1 {TranslateImage procedure} -constraints testImageType -setup { .c delete all update @@ -750,7 +744,7 @@ test canvImg-10.1 {TranslateImage procedure} -constraints testImageType -setup { } -cleanup { .c delete all image delete foo -} -result $result_10_1 +} -result {{foo display 2 4 6 8}} test canvImg-11.1 {TranslateImage procedure} -constraints testImageType -setup { .c delete all diff --git a/tests/image.test b/tests/image.test index da65a66..cac304f 100644 --- a/tests/image.test +++ b/tests/image.test @@ -357,12 +357,6 @@ test image-8.1 {Tk_ImageCmd procedure, "inuse" option} -constraints { catch {destroy .b} } -result [list 0 1] -if {[tk windowingsystem] == "aqua" && $tcl_platform(osVersion) > 18} { - # Aqua >= 10.14 will redraw the entire image in drawRect. - set result_9_1 {{foo display 0 0 30 15}} -} else { - set result_9_1 {{foo display 5 6 7 8}} -} test image-9.1 {Tk_ImageChanged procedure} -constraints testImageType -setup { .c delete all imageCleanup @@ -385,13 +379,8 @@ test image-9.1 {Tk_ImageChanged procedure} -constraints testImageType -setup { } -cleanup { .c delete all imageCleanup -} -result $result_9_1 -if {[tk windowingsystem] == "aqua" && $tcl_platform(osVersion) > 18} { - # Aqua >= 10.14 will redraw the entire image. - set result_9_2 {{foo display 0 0 30 15} {foo display 0 0 30 15}} -} else { - set result_9_2 {{foo display 5 6 25 9} {foo display 0 0 12 14}} -} +} -result {{foo display 5 6 7 8}} + test image-9.2 {Tk_ImageChanged procedure} -constraints testImageType -setup { .c delete all imageCleanup @@ -411,7 +400,7 @@ test image-9.2 {Tk_ImageChanged procedure} -constraints testImageType -setup { } -cleanup { .c delete all imageCleanup -} -result $result_9_2 +} -result {{foo display 5 6 25 9} {foo display 0 0 12 14}} test image-10.1 {Tk_GetImage procedure} -setup { imageCleanup diff --git a/tests/listbox.test b/tests/listbox.test index 14c5c97..8d4ed33 100644 --- a/tests/listbox.test +++ b/tests/listbox.test @@ -2800,13 +2800,13 @@ test listbox-21.16 {ListboxListVarProc, update vertical scrollbar} -setup { test listbox-22.1 {UpdateHScrollbar} -setup { destroy .l } -body { - listbox .l -font $fixed -width 10 -xscrollcommand "record x" set log {} + listbox .l -font $fixed -width 10 -xscrollcommand "record x" pack .l set timeout [after 500 {set log timeout}] vwait log .l insert end "0000000000" - update + update idletasks .l insert end "00000000000000000000" vwait log set log |