The expected behavior of Expose events has changed during the lifetime of Qt 5. We now want to be strict about when Expose events are sent, since they indicate that an immediate repaint is needed. Obscure events should also be sent at correct times to stop animations.
The Cocoa platform plugin has evolved to follow these changes, but has reached a state where there are potentially many sources for sending expose events, making it hard to reason about when they are sent. In addition the Cocoa platform plugin has special code paths for running under under QTestLib. It is desirable to simplify and unify the implementation.
We can use [NSView drawRect] as the canonical source of "you are on screen and should draw now". This is similar to what the iOS platform plugin already does.
https://codereview.qt-project.org/#/c/143798/ (Rework expose handling)
https://codereview.qt-project.org/#/c/146850/ (Document Expose event)
https://codereview.qt-project.org/#/c/146851/ (tst_qgl fix)
Related Bug Reports
Specific issues encountered:
Stricter Expose/Obscure handling breaks some tests:
- Some tests accidentally obscure a window (e.g. with another window), and still expect paint events. [Solution: fix the test]
- The GLWidget-as-viewport widget case:
The issue here is that the (top-level) QWindow for the QGraphicsView is completely obscured by the viewport window and won't receive the expose event. Possible solutions:
- QTest::waitForWindowExposed should use some other (self-contained) means to determine if a window is on screen.
- The native viewport widget is a QtWidgets internal matter: that module should make sure the top-level QWindow gets expose events (somehow).
- Fix the test: you can't wait for exposed on that window.
- Send expose immediately followed by Obscure
QCursor::setPos instability in tst_qabstractitemview.cpp
It's hard to see how is relevant.
- The QCursor::setPos() implementation on Cocoa should perhaps be made synchronous (the current one is async). Discussion is here: https://codereview.qt-project.org/#/c/145298/
tst_QBackingStore - crash
- -can be reproduced locally on OS X 10.10 (and probably below), does not happen on 10.11. Quite annoying chicken-egg problem: while we're inside platformWindow = createPlatformWindow(...), at some point here we also call
syncWindowState, which can end up in performZoom/performMiniaturize: etc.; this can trigger drawRect. Our QNSView will try to updateExposedState on a half-created window and at some point somewhere in
QCocoaBackingStore window()->handle() will be nullptr, since it's a 'platformWindow' from the assignment expression above - it's not assigned yet.
Update: this can be fixed if we add a guard in drawRect: if (!m_platformWindow->m_inConstructor) .... proceed with expose - I think there's nothing we can do about the fact that some object is, indeed, half-constructed and some
pointers are not valid yet.
- FAIL! : qmltest::ClickWindow::test_clickBothWindows() 'verify()' returned FALSE. () - cannot be reproduced if running as a standalone test
tst_qquickwindow::hideThenDelete(persistent:SG=false,GL=false) '(!window.isExposed())' returned FALSE. ()(and three more versions of the same test) -something weird: when running hideThenDelete the second time,
a window first receives expose event with null region (expected), but the there is the second expose event with non-null region (making QTRY_VERIFY(!exposed) to fail). Looks like a result of not running event loop properly
and delaying drawRect (actually, self.window is not even visible at this point).
https://bugreports.qt.io/browse/QTBUG-45975 - this one shows another (probably unrelated) problem that still can (again, probably) be addressed by the upcoming re-work in Cocoa plugin.
|For Gerrit Dashboard: QTBUG-50414|
|146564,4||qcocoacursor - change cursor position synchronously||dev||qt/qtbase||Status: ABANDONED||-1||0|
|146850,5||Document expose event behavior||dev||qt/qtbase||Status: MERGED||+2||0|
|146851,4||Wait for window expose on the viewport widget||dev||qt/qtbase||Status: MERGED||+2||0|
|199818,20||macOS: Send expose event at drawRect and trigger updates via setNeedsDisplay||dev||qt/qtbase||Status: MERGED||+2||0|