diff options
author | Axel Spoerl <axel.spoerl@qt.io> | 2023-11-27 16:33:12 +0100 |
---|---|---|
committer | Axel Spoerl <axel.spoerl@qt.io> | 2023-12-06 11:58:17 +0100 |
commit | 2f6fe3a26843ff68c5d3f9af0a2fc3cce6caac22 (patch) | |
tree | b8b8c5fb7c0f97c9a98edd858a28356a6ff27742 /src/plugins/platforms/xcb | |
parent | 3a57885c3766d4ae203650d60881988c374e4148 (diff) |
QXcbWindow: protect access to m_mapped with a QMutex
QXcbWindow::requestActivateWindow() is called from the main thread,
while handleMapNotifyEvent() is called from the XCB event thread.
In a data race, handleMapNotifyEvent sets m_mapped to true, before
requestActivateWindow() checks if it is false and sets
m_deferredActivation to true.
If that happens, a window activation is skipped until the next window
systems event is processed.
This is harmless in a normal application environment, where each mouse
move causes window systems events to be processed. In an autotest
environment, it causes flakiness, because an expected window activation
may or may not happen.
As a workaround, QApplicationPrivate::setActiveWindow() is frequently
called after QWidget::activateWindow() or QWindow::requestActivate(),
to set the active window on application level. In essence, this is
setting expected outcome of a skipped deferred activation by force.
This patch protects access to m_mapped and m_deferredActivation with a
QMutex in both methods. That prevents the data race and ensures all
deferred activations processed.
Calling QApplicationPrivate::setActiveWindow() after activation on
window/widget level becomes redundant.
Task-number: QTBUG-119287
Pick-to: 6.6 6.5
Change-Id: I2eee69292afe0ef6381880a10d4e8483c2c7cbfa
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 18 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 1 |
2 files changed, 14 insertions, 5 deletions
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 78f5b54fd1..bb49bddf3a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1461,11 +1461,14 @@ void QXcbWindow::requestActivateWindow() return; } - if (!m_mapped) { - m_deferredActivation = true; - return; + { + QMutexLocker locker(&m_mappedMutex); + if (!m_mapped) { + m_deferredActivation = true; + return; + } + m_deferredActivation = false; } - m_deferredActivation = false; updateNetWmUserTime(connection()->time()); QWindow *focusWindow = QGuiApplication::focusWindow(); @@ -1874,8 +1877,11 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) { if (event->window == m_window) { + m_mappedMutex.lock(); m_mapped = true; - if (m_deferredActivation) + const bool deferredActivation = m_deferredActivation; + m_mappedMutex.unlock(); + if (deferredActivation) requestActivateWindow(); QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); @@ -1885,7 +1891,9 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) { if (event->window == m_window) { + m_mappedMutex.lock(); m_mapped = false; + m_mappedMutex.unlock(); QWindowSystemInterface::handleExposeEvent(window(), QRegion()); } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index a04b4408a4..415dff09ba 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -222,6 +222,7 @@ protected: Qt::WindowStates m_windowState = Qt::WindowNoState; + QMutex m_mappedMutex; bool m_mapped = false; bool m_transparent = false; bool m_deferredActivation = false; |