macOS: Redraw window bottom corners after synchronous backing store flush
Flushing outside of the display cycle does not care about any ordering between views, including the NSThemeFrame responsible for drawing the rounded corners of the window. Since Qt Widgets is doing a lot of synchronous flushing (for now, until we plumb update() to requestUpdate(), or enable layer-backing), we add a workaround that explicitly draws the corners after flushing, just like the logic in [NSView displayIfNeeded]. This is the same workaround used by WebKit: https://trac.webkit.org/changeset/85376/webkit Change-Id: I884152cdb2685569704e577b64b5ae278ed82c21 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
dfdb94410a
commit
52ad5afe1c
@ -55,6 +55,7 @@ public:
|
||||
private:
|
||||
bool windowHasUnifiedToolbar() const;
|
||||
QImage::Format format() const Q_DECL_OVERRIDE;
|
||||
void redrawRoundedBottomCorners(CGRect) const;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -199,11 +199,62 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo
|
||||
if (shouldHandleViewLockManually)
|
||||
[view unlockFocus];
|
||||
|
||||
if (drawingOutsideOfDisplayCycle)
|
||||
if (drawingOutsideOfDisplayCycle) {
|
||||
redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
|
||||
[view.window flushWindow];
|
||||
}
|
||||
|
||||
// FIXME: Tie to changing window flags and/or mask instead
|
||||
[view invalidateWindowShadowIfNeeded];
|
||||
}
|
||||
|
||||
/*
|
||||
When drawing outside of the display cycle, which Qt Widget does a lot,
|
||||
we end up drawing over the NSThemeFrame, losing the rounded corners of
|
||||
windows in the process.
|
||||
|
||||
To work around this, until we've enabled updates via setNeedsDisplay and/or
|
||||
enabled layer-backed views, we ask the NSWindow to redraw the bottom corners
|
||||
if they intersect with the flushed region.
|
||||
|
||||
This is the same logic used internally by e.g [NSView displayIfNeeded],
|
||||
[NSRulerView _scrollToMatchContentView], and [NSClipView _immediateScrollToPoint:],
|
||||
as well as the workaround used by WebKit to fix a similar bug:
|
||||
|
||||
https://trac.webkit.org/changeset/85376/webkit
|
||||
*/
|
||||
void QCocoaBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const
|
||||
{
|
||||
#if !defined(QT_APPLE_NO_PRIVATE_APIS)
|
||||
Q_ASSERT(this->window()->handle());
|
||||
NSWindow *window = static_cast<QCocoaWindow *>(this->window()->handle())->nativeWindow();
|
||||
|
||||
static SEL intersectBottomCornersWithRect = NSSelectorFromString(
|
||||
[NSString stringWithFormat:@"_%s%s:", "intersectBottomCorners", "WithRect"]);
|
||||
if (NSMethodSignature *signature = [window methodSignatureForSelector:intersectBottomCornersWithRect]) {
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
invocation.target = window;
|
||||
invocation.selector = intersectBottomCornersWithRect;
|
||||
[invocation setArgument:&windowRect atIndex:2];
|
||||
[invocation invoke];
|
||||
|
||||
NSRect cornerOverlap = NSZeroRect;
|
||||
[invocation getReturnValue:&cornerOverlap];
|
||||
if (!NSIsEmptyRect(cornerOverlap)) {
|
||||
static SEL maskRoundedBottomCorners = NSSelectorFromString(
|
||||
[NSString stringWithFormat:@"_%s%s:", "maskRounded", "BottomCorners"]);
|
||||
if ((signature = [window methodSignatureForSelector:maskRoundedBottomCorners])) {
|
||||
invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
invocation.target = window;
|
||||
invocation.selector = maskRoundedBottomCorners;
|
||||
[invocation setArgument:&cornerOverlap atIndex:2];
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(windowRect);
|
||||
#endif
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
Reference in New Issue
Block a user