summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorculler <culler>2020-05-30 23:13:52 (GMT)
committerculler <culler>2020-05-30 23:13:52 (GMT)
commit8bfe6e9b964fb48650e31fac01c29de41ba63d44 (patch)
tree43c4905d1761c0474cc0a2336ed898b16c1b15ba /macosx
parentf5badcc4c99f99da82da6b138e7afb70f492305d (diff)
downloadtk-8bfe6e9b964fb48650e31fac01c29de41ba63d44.zip
tk-8bfe6e9b964fb48650e31fac01c29de41ba63d44.tar.gz
tk-8bfe6e9b964fb48650e31fac01c29de41ba63d44.tar.bz2
A partly but not completely successful attempt to control how drawRect is run.
Diffstat (limited to 'macosx')
-rw-r--r--macosx/tkMacOSXDraw.c40
-rw-r--r--macosx/tkMacOSXNotify.c115
-rw-r--r--macosx/tkMacOSXPrivate.h9
-rw-r--r--macosx/tkMacOSXSubwindows.c73
-rw-r--r--macosx/tkMacOSXWindowEvent.c133
-rw-r--r--macosx/tkMacOSXWm.c5
6 files changed, 253 insertions, 122 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index e56e666..d2d72e4 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -174,7 +174,9 @@ TkMacOSXBitmapRepFromDrawableRect(
if (cg_image) {
CGImageRelease(cg_image);
}
- } else if ((view = TkMacOSXDrawableView(mac_drawable)) != NULL) {
+ } else if (TkMacOSXDrawableView(mac_drawable) != NULL) {
+ TKContentView *tkview = (TKContentView *)view;
+
/*
* Convert Tk top-left to NSView bottom-left coordinates.
*/
@@ -197,7 +199,8 @@ TkMacOSXBitmapRepFromDrawableRect(
[view cacheDisplayInRect:view_rect toBitmapImageRep:bitmap_rep];
} else {
TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap.");
- [view setNeedsDisplay:YES];
+ [tkview setTkNeedsDisplay:YES];
+ [tkview setTkDirtyRect:[tkview bounds]];
return NULL;
}
} else {
@@ -1622,7 +1625,7 @@ TkMacOSXSetupDrawingContext(
if (dc.context) {
dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context);
} else if (win) {
- NSView *view = TkMacOSXDrawableView(macDraw);
+ TKContentView *view = (TKContentView *)TkMacOSXDrawableView(macDraw);
if (!view) {
Tcl_Panic("TkMacOSXSetupDrawingContext(): "
@@ -1636,31 +1639,22 @@ TkMacOSXSetupDrawingContext(
* 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.
- *
- * As an exception to the above, if mouse buttons are pressed at the
- * moment when we fail to obtain a valid context we schedule the entire
- * view for a redraw rather than just the clipping region. The purpose
- * of this is to make sure that scrollbars get updated correctly.
+ * display. We could try to optimize by computing a smaller dirty rect
+ * here.
*/
if (![NSApp isDrawing] || view != [NSView focusView]) {
- NSRect bounds = [view bounds];
- NSRect dirtyNS = bounds;
- if ([NSEvent pressedMouseButtons]) {
- [view setNeedsDisplay:YES];
- } else {
+ NSRect dirtyRect = [view bounds];
+ if (dc.clipRgn) {
+ CGRect clipRect;
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];
+ .ty = dirtyRect.size.height};
+ HIShapeGetBounds(dc.clipRgn, &clipRect);
+ clipRect = CGRectApplyAffineTransform(clipRect, t);
+ dirtyRect = NSRectFromCGRect(clipRect);
}
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:NSUnionRect([view tkDirtyRect], dirtyRect)];
canDraw = false;
goto end;
}
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index 985d7bc..f8ac50d 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -299,6 +299,70 @@ TkMacOSXNotifyExitHandler(
/*
*----------------------------------------------------------------------
*
+ * TkMacOSXDrawAllViews --
+ *
+ * This static function is meant to be run as an idle task. It attempts
+ * to redraw all views which have the tkNeedsDisplay property set to YES.
+ * This relies on a feature of [NSApp nextEventMatchingMask: ...] which
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Parts of windows my get redrawn.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+TkMacOSXDrawAllViews(
+ ClientData clientData)
+{
+ int count = 0, *dirtyCount = (int *)clientData;
+
+ for (NSWindow *window in [NSApp windows]) {
+ if ([[window contentView] isMemberOfClass:[TKContentView class]]) {
+ TKContentView *view = [window contentView];
+ if ([view tkNeedsDisplay]) {
+ count++;
+ if (dirtyCount) {
+ continue;
+ }
+ [view setNeedsDisplayInRect:[view tkDirtyRect]];
+ }
+ } else {
+ [window displayIfNeeded];
+ }
+ }
+ if (dirtyCount) {
+ *dirtyCount = count;
+ }
+
+ [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:GetRunLoopMode(TkMacOSXGetModalSession())
+ dequeue:NO];
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkMacOSXEventsSetupProc --
*
* This procedure implements the setup part of the MacOSX event source. It
@@ -334,11 +398,13 @@ TkMacOSXEventsSetupProc(
static const Tcl_Time zeroBlockTime = { 0, 0 };
[NSApp _resetAutoreleasePool];
- /*
- * Call this with dequeue=NO -- just checking if the queue is empty.
- */
+ /*
+ * 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.
+ */
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
NSEvent *currentEvent =
[NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
@@ -353,7 +419,7 @@ TkMacOSXEventsSetupProc(
} else if (!havePeriodicEvents){
/*
- * When the user is not generating events we schedule a "hearbeat"
+ * When the user is not generating events we schedule a "heartbeat"
* event to fire every 0.1 seconds. This helps to make the vwait
* command more responsive when there is no user input, e.g. when
* running the test suite.
@@ -362,6 +428,12 @@ 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)) {}
+ TkMacOSXDrawAllViews(NULL);
}
}
@@ -388,6 +460,7 @@ TkMacOSXEventsCheckProc(
int flags)
{
NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
+ int eventsFound = 0;
/*
* runloopMode will be nil if we are in a Tcl event loop.
@@ -408,7 +481,6 @@ TkMacOSXEventsCheckProc(
[NSApp _lockAutoreleasePool];
do {
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
modalSession = TkMacOSXGetModalSession();
testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
@@ -422,12 +494,12 @@ TkMacOSXEventsCheckProc(
if (testEvent && [[testEvent window] inLiveResize]) {
break;
}
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:YES];
if (currentEvent) {
+
/*
* Generate Xevents.
*/
@@ -436,9 +508,12 @@ TkMacOSXEventsCheckProc(
NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent];
Tcl_SetServiceMode(oldServiceMode);
if (processedEvent) {
+ eventsFound++;
+
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@" event: %@", currentEvent);
#endif
+
if (modalSession) {
[NSApp _modalSession:modalSession sendEvent:currentEvent];
} else {
@@ -446,6 +521,7 @@ TkMacOSXEventsCheckProc(
}
}
} else {
+
break;
}
} while (1);
@@ -453,8 +529,31 @@ TkMacOSXEventsCheckProc(
/*
* Now we can unlock the pool.
*/
-
[NSApp _unlockAutoreleasePool];
+
+ if (eventsFound == 0) {
+
+ /*
+ * We found no events for Tcl in this iteration of the Tcl event
+ * loop, so it should proceed to servicing idle tasks. We add an
+ * idle task to the end of the idle queue which will redisplay all
+ * of our dirty windows. We want this to happen after all other
+ * idle tasks have run so that all widgets will be configured
+ * before they are displayed. The drawRect method "borrows" the
+ * idle queue while drawing views. That is, it sends expose events
+ * which cause display procs to be posted as idle tasks and then
+ * runs an inner event loop to processes those idle tasks. We are
+ * trying to arrange for the idle queue to be empty when it starts
+ * that process and empty when it finishes.
+ */
+
+ int dirtyCount = 0;
+ TkMacOSXDrawAllViews(&dirtyCount);
+ if (dirtyCount > 0) {
+ Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL);
+ Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
+ }
+ }
}
}
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index be69fcd..fdd07ed 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -307,6 +307,8 @@ MODULE_SCOPE int TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE unsigned TkMacOSXAddVirtual(unsigned int keycode);
+MODULE_SCOPE void TkMacOSXWinNSBounds(TkWindow *winPtr, NSView *view,
+ NSRect *bounds);
#pragma mark Private Objective-C Classes
@@ -418,8 +420,12 @@ VISIBILITY_HIDDEN
@private
NSString *privateWorkingText;
Bool _needsRedisplay;
+ Bool _tkNeedsDisplay;
+ NSRect _tkDirtyRect;
}
@property Bool needsRedisplay;
+@property Bool tkNeedsDisplay;
+@property NSRect tkDirtyRect;
@end
@interface TKContentView(TKKeyEvent)
@@ -428,7 +434,8 @@ VISIBILITY_HIDDEN
@end
@interface TKContentView(TKWindowEvent)
-- (void) generateExposeEvents: (HIShapeRef) shape;
+ //(HIShapeRef) shape;
+- (void) generateExposeEvents: (NSRect) rect;
- (void) tkToolbarButton: (id) sender;
@end
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index 6602564..53e5bf6 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -157,6 +157,7 @@ XMapWindow(
winPtr->flags |= TK_MAPPED;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr)) {
+ TKContentView *view = [win contentView];
/*
* We want to activate Tk when a toplevel is mapped but we must not
@@ -169,7 +170,8 @@ XMapWindow(
TkMacOSXApplyWindowAttributes(winPtr, win);
[win setExcludedFromWindowsMenu:NO];
[NSApp activateIgnoringOtherApps:NO];
- [[win contentView] setNeedsDisplay:YES];
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect: [view bounds]];
if ([win canBecomeKeyWindow]) {
[win makeKeyAndOrderFront:NSApp];
} else {
@@ -215,7 +217,9 @@ XMapWindow(
if ([NSApp isDrawing]) {
[[win contentView] setNeedsRedisplay:YES];
} else {
- [[win contentView] setNeedsDisplay:YES];
+ TKContentView *view = [win contentView];
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:[view bounds]];
}
/*
@@ -332,7 +336,9 @@ XUnmapWindow(
if ([NSApp isDrawing]) {
[[win contentView] setNeedsRedisplay:YES];
} else {
- [[win contentView] setNeedsDisplay:YES];
+ TKContentView *view = [win contentView];
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:[view bounds]];
}
return Success;
}
@@ -986,8 +992,9 @@ InvalViewRect(
void *ref)
{
static CGAffineTransform t;
- NSView *view = ref;
-
+ TKContentView *view = ref;
+ NSRect dirtyRect;
+
if (!view) {
return paramErr;
}
@@ -997,8 +1004,9 @@ InvalViewRect(
NSHeight([view bounds]));
break;
case kHIShapeEnumerateRect:
- [view setNeedsDisplayInRect:NSRectFromCGRect(
- CGRectApplyAffineTransform(*rect, t))];
+ dirtyRect = NSRectFromCGRect(CGRectApplyAffineTransform(*rect, t));
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:NSUnionRect([view tkDirtyRect], dirtyRect)];
break;
}
return noErr;
@@ -1275,16 +1283,15 @@ TkMacOSXInvalClipRgns(
*
* TkMacOSXWinBounds --
*
- * Given a Tk window this function determines the windows bounds in
- * relation to the Macintosh window's coordinate system. This is also the
- * same coordinate system as the Tk toplevel window in which this window
- * is contained.
+ * Given a Tk window this function determines the window's bounds in
+ * the coordinate system of the Tk toplevel window in which this window
+ * is contained. This fills in a Rect struct.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * Fills in a Rect.
*
*----------------------------------------------------------------------
*/
@@ -1307,16 +1314,15 @@ TkMacOSXWinBounds(
*
* TkMacOSXWinCGBounds --
*
- * Given a Tk window this function determines the windows bounds in
- * relation to the Macintosh window's coordinate system. This is also the
- * same coordinate system as the Tk toplevel window in which this window
- * is contained.
+ * Given a Tk window this function determines the window's bounds in
+ * the coordinate system of the Tk toplevel window in which this window
+ * is contained. This fills in a CGRect struct.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * Fill in a CGRect.
*
*----------------------------------------------------------------------
*/
@@ -1331,6 +1337,39 @@ TkMacOSXWinCGBounds(
bounds->size.width = winPtr->changes.width;
bounds->size.height = winPtr->changes.height;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXWinNSBounds --
+ *
+ * Given a Tk window this function determines the window's bounds in
+ * the coordinate system of the TKContentView in which this Tk window
+ * is contained, which has the origin at the lower left corner. This
+ * fills in an NSRect struct and requires the TKContentView as a
+ * parameter
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Fills in an NSRect.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXWinNSBounds(
+ TkWindow *winPtr,
+ NSView *view,
+ NSRect *bounds)
+{
+ bounds->size.width = winPtr->changes.width;
+ bounds->size.height = winPtr->changes.height;
+ bounds->origin.x = winPtr->privatePtr->xOff;
+ bounds->origin.y = ([view bounds].size.height -
+ bounds->size.height -
+ winPtr->privatePtr->yOff);
+}
/*
*----------------------------------------------------------------------
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 76b2b04..6e8f7c4 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -30,8 +30,8 @@
* Declaration of functions used only in this file
*/
-static int GenerateUpdates(HIShapeRef updateRgn,
- CGRect *updateBounds, TkWindow *winPtr);
+static int GenerateUpdates(
+ CGRect *updateBounds, TkWindow *winPtr);
static int GenerateActivateEvents(TkWindow *winPtr,
int activeFlag);
static void DoWindowActivate(ClientData clientData);
@@ -407,16 +407,29 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
int
TkpAppCanDraw(Tk_Window tkwin) {
- if (![NSApp isDrawing]) {
- return 0;
- }
+ int result;
if (tkwin) {
TkWindow *winPtr = (TkWindow *)tkwin;
- NSView *view = TkMacOSXDrawableView(winPtr->privatePtr);
- return (view == [NSView focusView]);
+ TKContentView *view = (TKContentView *) TkMacOSXDrawableView(
+ winPtr->privatePtr);
+ result = ([NSApp isDrawing] && view == [NSView focusView]);
+#if 0
+ printf("TkAppCanDraw: %s %d %d \n", Tk_PathName(tkwin),
+ [NSApp isDrawing], (view == [NSView focusView]));
+ if (!result) {
+ NSRect dirtyRect;
+ TkMacOSXWinNSBounds(winPtr, view, &dirtyRect);
+ printf("TkpAppCanDraw: dirtyRect for %s is %s\n",
+ Tk_PathName(tkwin),
+ NSStringFromRect(dirtyRect).UTF8String);
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:dirtyRect];
+ }
+#endif
} else {
- return 1;
+ result = [NSApp isDrawing];
}
+ return result;
}
/*
@@ -424,9 +437,9 @@ TkpAppCanDraw(Tk_Window tkwin) {
*
* GenerateUpdates --
*
- * Given a Macintosh update region and a Tk window this function geneates
+ * Given an update rectangle and a Tk window, this function geneates
* an X Expose event for the window if it meets the update region. The
- * function will then recursivly have each damaged window generate Expose
+ * function will then recursively have each damaged window generate Expose
* events for its child windows.
*
* Results:
@@ -440,39 +453,23 @@ TkpAppCanDraw(Tk_Window tkwin) {
static int
GenerateUpdates(
- HIShapeRef updateRgn,
CGRect *updateBounds,
TkWindow *winPtr)
{
TkWindow *childPtr;
XEvent event;
CGRect bounds, damageBounds;
- HIShapeRef boundsRgn, damageRgn;
TkMacOSXWinCGBounds(winPtr, &bounds);
if (!CGRectIntersectsRect(bounds, *updateBounds)) {
return 0;
}
- if (!HIShapeIntersectsRect(updateRgn, &bounds)) {
- return 0;
- }
/*
* Compute the bounding box of the area that the damage occured in.
*/
- boundsRgn = HIShapeCreateWithRect(&bounds);
- damageRgn = HIShapeCreateIntersection(updateRgn, boundsRgn);
- if (HIShapeIsEmpty(damageRgn)) {
- CFRelease(damageRgn);
- CFRelease(boundsRgn);
- return 0;
- }
- HIShapeGetBounds(damageRgn, &damageBounds);
-
- CFRelease(damageRgn);
- CFRelease(boundsRgn);
-
+ damageBounds = CGRectIntersection(bounds, *updateBounds);
event.xany.serial = LastKnownRequestProcessed(Tk_Display(winPtr));
event.xany.send_event = false;
event.xany.window = Tk_WindowId(winPtr);
@@ -486,7 +483,7 @@ GenerateUpdates(
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
#ifdef TK_MAC_DEBUG_DRAWING
- TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
+ TKLog(@"Exposed %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
event.xexpose.y, event.xexpose.width, event.xexpose.height);
#endif
@@ -499,7 +496,7 @@ GenerateUpdates(
if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) {
continue;
}
- GenerateUpdates(updateRgn, updateBounds, childPtr);
+ GenerateUpdates(updateBounds, childPtr);
}
/*
@@ -509,7 +506,7 @@ GenerateUpdates(
if (Tk_IsContainer(winPtr)) {
childPtr = TkpGetOtherWindow(winPtr);
if (childPtr != NULL && Tk_IsMapped(childPtr)) {
- GenerateUpdates(updateRgn, updateBounds, childPtr);
+ GenerateUpdates(updateBounds, childPtr);
}
/*
@@ -928,10 +925,10 @@ ConfigureRestrictProc(
*/
static void
-RedisplayView(
+RedisplayView(
ClientData clientdata)
{
- NSView *view = (NSView *) clientdata;
+ TKContentView *view = (TKContentView *) clientdata;
/*
* Make sure that we are not trying to displaying a view that no longer
@@ -941,7 +938,8 @@ RedisplayView(
for (NSWindow *w in [NSApp windows]) {
if ([w contentView] == view) {
- [view setNeedsDisplay:YES];
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:[view bounds]];
break;
}
}
@@ -951,13 +949,13 @@ RedisplayView(
- (void) drawRect: (NSRect) rect
{
- const NSRect *rectsBeingDrawn;
- NSInteger rectsBeingDrawnCount;
#ifdef TK_MAC_DEBUG_DRAWING
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
- if (winPtr) fprintf(stderr, "drawRect: drawing %s\n",
- Tk_PathName(winPtr));
+ if (winPtr) {
+ fprintf(stderr, "drawRect: drawing %s in %s\n",
+ Tk_PathName(winPtr), NSStringFromRect(rect).UTF8String);
+ }
#endif
/*
@@ -974,23 +972,11 @@ RedisplayView(
[NSApp setIsDrawing: YES];
- [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
- CGFloat height = [self bounds].size.height;
- HIMutableShapeRef drawShape = HIShapeCreateMutable();
-
- while (rectsBeingDrawnCount--) {
- CGRect r = NSRectToCGRect(*rectsBeingDrawn++);
-
#ifdef TK_MAC_DEBUG_DRAWING
- fprintf(stderr, "drawRect: %dx%d@(%d,%d)\n", (int)r.size.width,
- (int)r.size.height, (int)r.origin.x, (int)r.origin.y);
+ fprintf(stderr, "drawRect: %s\n", NSStringFromRect(rect).UTF8String;
#endif
- r.origin.y = height - (r.origin.y + r.size.height);
- HIShapeUnionWithRect(drawShape, &r);
- }
- [self generateExposeEvents:(HIShapeRef)drawShape];
- CFRelease(drawShape);
+ [self generateExposeEvents:rect];
[NSApp setIsDrawing: NO];
if ([self needsRedisplay]) {
@@ -998,6 +984,9 @@ RedisplayView(
Tcl_DoWhenIdle(RedisplayView, self);
}
+ [self setTkNeedsDisplay:NO];
+ [self setTkDirtyRect:NSZeroRect];
+
#ifdef TK_MAC_DEBUG_DRAWING
fprintf(stderr, "drawRect: done.\n");
#endif
@@ -1056,9 +1045,7 @@ RedisplayView(
* Generate and process expose events to redraw the window.
*/
- HIRect bounds = NSRectToCGRect([self bounds]);
- HIShapeRef shape = HIShapeCreateWithRect(&bounds);
- [self generateExposeEvents: shape];
+ [self generateExposeEvents: [self bounds]];
[w displayIfNeeded];
/*
@@ -1076,11 +1063,11 @@ RedisplayView(
* pending idle events are processed so the drawing will actually take place.
*/
-- (void) generateExposeEvents: (HIShapeRef) shape
+- (void) generateExposeEvents: (NSRect) rect
{
unsigned long serial;
- CGRect updateBounds;
int updatesNeeded;
+ CGRect updateBounds;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
ClientData oldArg;
Tk_RestrictProc *oldProc;
@@ -1089,20 +1076,18 @@ RedisplayView(
}
/*
- * Generate Tk Expose events.
- */
-
- HIShapeGetBounds(shape, &updateBounds);
-
- /*
- * All of these events will share the same serial number.
+ * Generate Tk Expose events. All of these events will share the same
+ * serial number.
*/
-
- serial = LastKnownRequestProcessed(Tk_Display(winPtr));
- updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr);
-
+
+ updateBounds = NSRectToCGRect(rect);
+ updateBounds.origin.y = ([self bounds].size.height - updateBounds.origin.y
+ - updateBounds.size.height);
+ updatesNeeded = GenerateUpdates(&updateBounds, winPtr);
if (updatesNeeded) {
+ serial = LastKnownRequestProcessed(Tk_Display(winPtr));
+
/*
* First process all of the Expose events.
*/
@@ -1120,9 +1105,10 @@ RedisplayView(
* effect.)
*
* Fortunately, Tk schedules all drawing to be done while Tcl is idle.
- * So we can do the drawing by processing all of the idle events that
- * were created when the expose events were processed.
+ * So we can do the drawing now by processing all of the idle events
+ * that were created when the expose events were processed.
*/
+
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
}
}
@@ -1202,10 +1188,15 @@ RedisplayView(
- (BOOL) isOpaque
{
NSWindow *w = [self window];
- return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) ||
- ![w isOpaque]) ? NO : YES);
+ return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) ||
+ ![w isOpaque]) ? NO : YES);
}
+/*
+ * On Catalina this is never called and drawRect clips to the rect that
+ * is passed to it by AppKit.
+ */
+
- (BOOL) wantsDefaultClipping
{
return NO;
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index cab2b9a..1b51479 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -6201,13 +6201,14 @@ TkpRedrawWidget(Tk_Window tkwin) {
}
w = TkMacOSXDrawableWindow(winPtr->window);
if (w) {
- NSView *view = [w contentView];
+ TKContentView *view = [w contentView];
TkMacOSXWinBounds(winPtr, &tkBounds);
bounds = NSMakeRect(tkBounds.left,
[view bounds].size.height - tkBounds.bottom,
tkBounds.right - tkBounds.left,
tkBounds.bottom - tkBounds.top);
- [view setNeedsDisplayInRect:bounds];
+ [view setTkNeedsDisplay:YES];
+ [view setTkDirtyRect:bounds];
}
}