Attachment "06d8246baf-postponedSNDIR.diff" to
ticket [06d8246b]
added by
chrstphrchvz
2020-05-03 05:21:14.
diff --git macosx/tkMacOSXDraw.c macosx/tkMacOSXDraw.c
index e56e6665d..bad423261 100644
--- macosx/tkMacOSXDraw.c
+++ macosx/tkMacOSXDraw.c
@@ -1634,34 +1634,40 @@ TkMacOSXSetupDrawingContext(
* 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.
+ * The region to be drawn into must also intersect with the area
+ * for the current drawRect call.
*
* 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.
*/
- if (![NSApp isDrawing] || view != [NSView focusView]) {
- NSRect bounds = [view bounds];
- NSRect dirtyNS = bounds;
- if ([NSEvent pressedMouseButtons]) {
- [view setNeedsDisplay:YES];
- } else {
- 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];
- }
+ NSRect bounds = [view bounds];
+ NSRect dirtyNS = bounds;
+ if (dc.clipRgn) {
+ // Don't bother initializing; will be overwritten with dc.clipRgn
+ //CGRect dirtyCG = NSRectToCGRect(dirtyNS);
+ CGRect dirtyCG;
+ HIShapeGetBounds(dc.clipRgn, &dirtyCG);
+ CGAffineTransform t = {
+ .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
+ .ty = dirtyNS.size.height
+ };
+ dirtyNS = NSRectToCGRect(CGRectApplyAffineTransform(dirtyCG, t));
+ }
+ if (![NSApp isDrawing]) {
+ [view setNeedsDisplayInRect:dirtyNS];
canDraw = false;
+ } else if (view != [NSView focusView] || ![view needsToDrawRect:dirtyNS]) {
+ // Try calling setNeedsDisplayInRect: later when not in drawRect.
+ TkMacOSXPostponedSNDIR *holder = ckalloc(sizeof(TkMacOSXPostponedSNDIR));
+ holder->view = view;
+ holder->dirtyRect = dirtyNS;
+ Tcl_CreateTimerHandler(0, TkMacOSXDoPostponedSNDIR, holder);
+ canDraw = false;
+ }
+ if (!canDraw) {
goto end;
}
@@ -1823,6 +1829,41 @@ TkMacOSXRestoreDrawingContext(
#endif /* TK_MAC_DEBUG */
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXDoPostponedSNDIR --
+ *
+ * Check whether currently in drawRect:, and if not, do the call to
+ * [view setNeedsDisplayInRect:dirtyRect] which was postponed either in
+ * TkMacOSXSetupDrawingContext, or by an earlier TkMacOSXDoPostponedSNDIR
+ * attempt, due to already being in drawRect:. Otherwise if in drawRect:,
+ * postpone again.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Either setNeedsDisplayInRect: is called and the holder for the call's
+ * arguments is freed, or it is postponed again with a new timer handler.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXDoPostponedSNDIR(
+ ClientData clientData)
+{
+ TkMacOSXPostponedSNDIR *holder = clientData;
+ if (![NSApp isDrawing]) {
+ [holder->view setNeedsDisplayInRect:holder->dirtyRect];
+ ckfree(holder);
+ } else {
+ // Postpone again
+ Tcl_CreateTimerHandler(0, TkMacOSXDoPostponedSNDIR, holder);
+ }
+}
+
/*
*----------------------------------------------------------------------
*
diff --git macosx/tkMacOSXInt.h macosx/tkMacOSXInt.h
index 9cb75d2ba..a91cb57f2 100644
--- macosx/tkMacOSXInt.h
+++ macosx/tkMacOSXInt.h
@@ -186,6 +186,12 @@ MODULE_SCOPE void TkpFreeGCCache(GC gc);
#define TK_LAYOUT_WITH_BASE_CHUNKS 1
#define TK_DRAW_IN_CONTEXT 1
+// Structure to hold arguments for postponed setNeedsDisplayInRect: calls
+typedef struct {
+ NSView *view;
+ NSRect dirtyRect;
+} TkMacOSXPostponedSNDIR;
+
/*
* Prototypes of internal procs not in the stubs table.
*/
@@ -204,6 +210,7 @@ MODULE_SCOPE Bool TkpAppIsDrawing(void);
MODULE_SCOPE void TkpDisplayWindow(Tk_Window tkwin);
MODULE_SCOPE Bool TkTestLogDisplay(void);
MODULE_SCOPE Bool TkMacOSXInDarkMode(Tk_Window tkwin);
+MODULE_SCOPE void TkMacOSXDoPostponedSNDIR(ClientData clientData);
/*
* Include the stubbed internal platform-specific API.