From 457ae8f19093c282a0f54d4e3b29e68c2a2477dc Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Sat, 9 May 2020 17:05:32 +0800 Subject: [PATCH 08/15] qwaylanddisplay: Wakeup main event dispatcher when events pending The socket might not be able to generate poll events to wakeup the main event dispatcher when there're multiple wayland clients(e.g. waylandsink) reading it. So let's create a extra thread to check the wayland display event queue for pending events and wakeup the main event dispatcher. Signed-off-by: Jeffy Chen --- src/client/qwaylanddisplay.cpp | 50 +++++++++++++++++++++++++++++++++- src/client/qwaylanddisplay_p.h | 2 ++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index ba4ce93..d07477a 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -83,6 +83,8 @@ #include +#include + #include #include @@ -92,6 +94,48 @@ namespace QtWaylandClient { Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging +class QWaylandDisplayThread : public QThread +{ +public: + QWaylandDisplayThread(struct wl_display *display); + ~QWaylandDisplayThread(); + +protected: + virtual void run() override; + +private: + struct wl_display *mDisplay = nullptr; + bool quit; +}; + +QWaylandDisplayThread::QWaylandDisplayThread(struct wl_display *display) + : mDisplay(display), quit(false) +{ + start(); +} + +QWaylandDisplayThread::~QWaylandDisplayThread() +{ + quit = true; + wait(); +} + +void QWaylandDisplayThread::run() +{ + while (!quit) { + if (wl_display_prepare_read(mDisplay) != 0) { + // wakeup dispatcher for pending events + if (auto *dispatcher = QCoreApplication::eventDispatcher()) + dispatcher->wakeUp(); + } else { + wl_display_flush(mDisplay); + wl_display_cancel_read(mDisplay); + } + + usleep(100000); + } +} + struct wl_surface *QWaylandDisplay::createSurface(void *handle) { struct wl_surface *surface = mCompositor.create_surface(); @@ -160,6 +204,8 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) qCWarning(lcQpaWayland, "failed to create xkb context"); #endif + mThread = new QWaylandDisplayThread(mDisplay); + forceRoundTrip(); if (!mWaitingScreens.isEmpty()) { @@ -186,8 +232,10 @@ QWaylandDisplay::~QWaylandDisplay(void) #if QT_CONFIG(cursor) qDeleteAll(mCursorThemes); #endif - if (mDisplay) + if (mDisplay) { + delete mThread; wl_display_disconnect(mDisplay); + } } void QWaylandDisplay::ensureScreen() diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 188e913..42b6c09 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -109,6 +109,7 @@ class QWaylandSurface; class QWaylandShellIntegration; class QWaylandCursor; class QWaylandCursorTheme; +class QWaylandDisplayThread; typedef void (*RegistryListener)(void *data, struct wl_registry *registry, @@ -280,6 +281,7 @@ private: struct wl_callback *mSyncCallback = nullptr; static const wl_callback_listener syncCallbackListener; QReadWriteLock m_frameQueueLock; + QWaylandDisplayThread *mThread = nullptr; bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull(); bool mUsingInputContextFromCompositor = false; -- 2.20.1