From 1c4a98ccc2b05ae1a1bba6c3f1d67831c7a82d1f Mon Sep 17 00:00:00 2001 From: YeShanShan Date: Mon, 11 Sep 2023 14:49:12 +0800 Subject: [PATCH] fix: Crashed when received xcb event in debug wayland plugin `setProperty` will call sendEvent, and the `handle->m_base` is construct in main thread but called in DXcbEventFilter's thread, It caused Q_ASSERT failed because `sendEvent` in different thread. We handle xcb event in main thread. --- src/dnativesettings.h | 7 ++++--- src/global.cpp | 21 +++++++++++++++++++++ src/global.h | 13 +++++++++++++ tests/CMakeLists.txt | 3 ++- tests/src/ut_global.cpp | 21 +++++++++++++++++++++ wayland/dwayland/dxsettings.cpp | 15 +++++++++++---- 6 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/dnativesettings.h b/src/dnativesettings.h index 5821dcb7..39da1716 100644 --- a/src/dnativesettings.h +++ b/src/dnativesettings.h @@ -5,12 +5,13 @@ #ifndef DNATIVESETTINGS_H #define DNATIVESETTINGS_H -#include "global.h" - -#include #define protected public #include #undef protected + +#include "global.h" + +#include #include DPP_BEGIN_NAMESPACE diff --git a/src/global.cpp b/src/global.cpp index 2cc6470b..644ab564 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -17,3 +17,24 @@ QWindow * fromQtWinId(WId id) { } return window; }; + +DPP_BEGIN_NAMESPACE + +RunInThreadProxy::RunInThreadProxy(QObject *parent) + : QObject(parent) +{ +} + +void RunInThreadProxy::proxyCall(FunctionType func) +{ + QObject *receiver = parent(); + if (!receiver) + receiver = qApp; + + QObject scope; + connect(&scope, &QObject::destroyed, receiver, [func]() { + (func)(); + }, Qt::QueuedConnection); +} + +DPP_END_NAMESPACE diff --git a/src/global.h b/src/global.h index 0806a64a..b92676c9 100644 --- a/src/global.h +++ b/src/global.h @@ -6,6 +6,7 @@ #define GLOBAL_H #include +#include #define MOUSE_MARGINS 10 @@ -112,4 +113,16 @@ enum DeviceType { class QWindow; QWindow * fromQtWinId(WId id); +DPP_BEGIN_NAMESPACE + +class RunInThreadProxy : public QObject +{ + Q_OBJECT +public: + using FunctionType = std::function; + explicit RunInThreadProxy(QObject *parent = nullptr); + void proxyCall(FunctionType func); + +}; +DPP_END_NAMESPACE #endif // GLOBAL_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ff9119d9..63071769 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,7 +4,7 @@ project(ut-platformplugins) -find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Widgets Test) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Widgets Concurrent Test) find_package(GTest REQUIRED) if(${QT_VERSION_MAJOR} STREQUAL "5") find_package(Qt5 REQUIRED COMPONENTS XcbQpa X11Extras EdidSupport XkbCommonSupport) @@ -44,6 +44,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::GuiPrivate Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Test GTest::GTest gmock diff --git a/tests/src/ut_global.cpp b/tests/src/ut_global.cpp index a0b3b299..776553b0 100644 --- a/tests/src/ut_global.cpp +++ b/tests/src/ut_global.cpp @@ -3,7 +3,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include +#include #include +#include +#include #include "global.h" @@ -34,3 +37,21 @@ TEST_F(TGlobal, fromQtWinId) } +TEST(TRunInThreadProxy, callInThread) +{ + DPP_USE_NAMESPACE; + + QThread *calledThread = nullptr; + + auto feature = QtConcurrent::run([&calledThread]() { + RunInThreadProxy proxy; + proxy.proxyCall([&calledThread]() { + calledThread = QThread::currentThread(); + }); + }); + feature.waitForFinished(); + QCoreApplication::processEvents(); + + ASSERT_EQ(qApp->thread(), calledThread); +} + diff --git a/wayland/dwayland/dxsettings.cpp b/wayland/dwayland/dxsettings.cpp index 0f4df185..90ecf981 100644 --- a/wayland/dwayland/dxsettings.cpp +++ b/wayland/dwayland/dxsettings.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "dxsettings.h" +#include DPP_BEGIN_NAMESPACE @@ -11,6 +12,7 @@ class DXcbEventFilter : public QThread public: DXcbEventFilter(xcb_connection_t *connection) : m_connection(connection) + , m_threadProxy(new RunInThreadProxy(qApp)) { QThread::start(); } @@ -21,14 +23,18 @@ class DXcbEventFilter : public QThread uint response_type = event->response_type & ~0x80; switch (response_type) { case XCB_PROPERTY_NOTIFY: { - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; - DXcbXSettings::handlePropertyNotifyEvent(pn); + m_threadProxy->proxyCall([event]() { + xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + DXcbXSettings::handlePropertyNotifyEvent(pn); + }); break; } case XCB_CLIENT_MESSAGE: { - xcb_client_message_event_t *ev = reinterpret_cast(event); - DXcbXSettings::handleClientMessageEvent(ev); + m_threadProxy->proxyCall([event]() { + xcb_client_message_event_t *ev = reinterpret_cast(event); + DXcbXSettings::handleClientMessageEvent(ev); + }); break; } } @@ -37,6 +43,7 @@ class DXcbEventFilter : public QThread private: xcb_connection_t *m_connection; + RunInThreadProxy *m_threadProxy = nullptr; }; xcb_connection_t *DXSettings::xcb_connection = nullptr;