diff options
authorTor Arne Vestbø <>2018-07-18 23:51:58 +0200
committerTor Arne Vestbø <>2018-08-28 10:28:47 +0000
commit2ef53620115037015d44d9629ee1e12da44be715 (patch)
parentac5e617596625504f4bd5d8bdb8cabb51b575a87 (diff)
QMacStyle: Make helper-NSViews layer-backed
This prevents the view from triggering display of its superview when being temporarily added, which is both inefficient and causes issues when those dirty-rects are wrong due to the wrong frame position of the added view. The additional drawRect: calls and corresponding expose events resulting from the needsDisplay calls also caused repaint issues in Qt Widgets. QWidgetBackingStore doesn't seem to take the exposed region into account for an expose event, and will try to flush all dirty regions. Some of those may be outside the exposed region, and will be clipped away by the window system, never ending up on the screen, but with Widgets still thinking it has flushed all dirty regions. This is a separate issue, possibly solvable by setting the wantsDefaultClipping property on NSView to NO, but this needs further testing, so applying this commit as workaround makes sense, even if it's just hiding the real bug. Task-number: QTBUG-67998 Task-number: QTBUG-68023 Task-number: QTBUG-69990 Task-number: QTBUG-69740 Task-number: QTBUG-69292 Task-number: QTBUG-69332 Reviewed-by: Timur Pocheptsov <> (cherry picked from commit 38979332d0a66666ebd178bccd7e7a2b300a7e42) Change-Id: I4ef3fef29f749daa4f3a11fe9186ae77b359f966 Reviewed-by: Simon Hausmann <> Reviewed-by: Morten Johan Sørvig <>
1 files changed, 31 insertions, 5 deletions
diff --git a/src/plugins/styles/mac/ b/src/plugins/styles/mac/
index 45da5fbd84..3405f01046 100644
--- a/src/plugins/styles/mac/
+++ b/src/plugins/styles/mac/
@@ -1880,20 +1880,46 @@ NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const
return cell;
-void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRectF &qtRect, QPainter *p,
+void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p,
__attribute__((noescape)) DrawRectBlock drawRectBlock) const
QMacCGContext ctx(p);
setupNSGraphicsContext(ctx, YES);
- const CGRect rect = qtRect.toCGRect();
+ // FIXME: The rect that we get in is relative to the widget that we're drawing
+ // style on behalf of, and doesn't take into account the offset of that widget
+ // to the widget that owns the backingstore, which we are placing the native
+ // view into below. This means most of the views are placed in the upper left
+ // corner of backingStoreNSView, which does not map to where the actual widget
+ // is, and which may cause problems such as triggering a setNeedsDisplay of the
+ // backingStoreNSView for the wrong rect. We work around this by making the view
+ // layer-backed, which prevents triggering display of the backingStoreNSView, but
+ // but there may be other issues lurking here due to the wrong position. QTBUG-68023
+ view.wantsLayer = YES;
+ // FIXME: We are also setting the frame of the incoming view a lot at the call
+ // sites of this function, making it unclear who's actually responsible for
+ // maintaining the size and position of the view. In theory the call sites
+ // should ensure the _size_ of the view is correct, and then let this code
+ // take care of _positioning_ the view at the right place inside backingStoreNSView.
+ // For now we pass on the rect as is, to prevent any regressions until this
+ // can be investigated properly.
+ view.frame = rect.toCGRect();
[backingStoreNSView addSubview:view];
- view.frame = rect;
+ // FIXME: Based on the code below, this method isn't drawing an NSView into
+ // a rect, it's drawing _part of the NSView_, defined by the incoming clip
+ // or dirty rect, into the current graphics context. We're doing some manual
+ // translations at the call sites that would indicate that this relationship
+ // is a bit fuzzy.
+ const CGRect dirtyRect = rect.toCGRect();
if (drawRectBlock)
- drawRectBlock(ctx, rect);
+ drawRectBlock(ctx, dirtyRect);
- [view drawRect:rect];
+ [view drawRect:dirtyRect];
[view removeFromSuperviewWithoutNeedingDisplay];