summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkFont.c2
-rw-r--r--macosx/tkMacOSXDraw.c55
-rw-r--r--macosx/tkMacOSXNotify.c68
-rw-r--r--macosx/tkMacOSXPrivate.h1
-rw-r--r--macosx/tkMacOSXWindowEvent.c40
-rw-r--r--tests/canvImg.test8
-rw-r--r--tests/image.test17
-rw-r--r--tests/listbox.test4
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