Commit d8c210d7 authored by Tor Arne Vestbø's avatar Tor Arne Vestbø
Browse files

macOS: Prevent flickering when resizing window rendered to by separate thread

When a window is resized AppKit groups all updates to the view frames and
corresponding layer bounds, so that the result of the resize is visually
atomic, but this only works for the main thread.

http://openradar.appspot.com/radar?id=4990815088672768

When a separate thread renders to one of the views in the window, it may
result in the view and its layer updating its bounds visually before the
resize has been visually reflected for the window itself and its border.

To ensure visually atomic updates, we disable all screen updates for the
process during resizing. This is the same workaround used by e.g. the
NSOpenPanel class, which renders the content of the view out of process,
and by Chromium for a similar use-case:

https://chromium-review.googlesource.com/c/chromium/src/+/798774



Ideally we'd do this only for the window that is being resized, but there's
no known API to do that. The deprecated [NSWindow disableScreenUpdatesUntilFlush]
is a no-op these days, and used NSDisableScreenUpdates internally anyways).

Fixes: QTBUG-69321
Change-Id: I84de714782278f2e0b2b2e1eb245c30810cb3023
Reviewed-by: default avatarMorten Johan Sørvig <morten.sorvig@qt.io>
Reviewed-by: default avatarSimon Hausmann <simon.hausmann@qt.io>
Showing with 30 additions and 0 deletions
......@@ -106,6 +106,36 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
return QCocoaScreen::mapToNative(maximizedFrame);
}
#pragma clang diagnostic push
// NSDisableScreenUpdates and NSEnableScreenUpdates are deprecated, but the
// NSAnimationContext API that replaces them doesn't handle the use-case of
// cross-thread screen update synchronization.
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)frameSize
{
qCDebug(lcQpaWindow) << window << "will resize to" << QSizeF::fromCGSize(frameSize)
<< "- disabling screen updates temporarily";
// There may be separate threads rendering to CA layers in this window,
// and if any of them do a swap while the resize is still in progress,
// the visual bounds of that layer will be updated before the visual
// bounds of the window frame, resulting in flickering while resizing.
// To prevent this we disable screen updates for the whole process until
// the resize is complete, which makes the whole thing visually atomic.
NSDisableScreenUpdates();
return frameSize;
}
- (void)windowDidResize:(NSNotification *)notification
{
NSWindow *window = notification.object;
qCDebug(lcQpaWindow) << window << "was resized - re-enabling screen updates";
NSEnableScreenUpdates();
}
#pragma clang diagnostic pop
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
{
Q_UNUSED(window);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment