diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2018-09-05 22:36:21 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2018-09-11 16:36:50 +0000 |
commit | d8c210d7f576fc54b41ad06c061ece7cadeed648 (patch) | |
tree | 18e9de244c23995952118604e2d8f04552f4240d /src/plugins/platforms | |
parent | 017ac02ec459378074a44487f171cc909e947f4a (diff) |
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: Morten Johan Sørvig <morten.sorvig@qt.io>
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/cocoa/qnswindowdelegate.mm | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 1c21879a89..97309ea990 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -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); |