From 9d5d8d087102cb33f916ef8c3a512589fa5f4464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 7 Nov 2014 11:41:37 +0100 Subject: [PATCH] Display can start the server before QCoreApplication is created Event dispatching in Display requires a QSocketNotifier which requires the QCoreApplication to be created. This requirement renders it impossible to create the server before the QCoreApplication is created. But there are use cases which need this: Let's assume we want to integrate a wayland server into an existing X11 dependent application which uses QApplication and enforces the xcb plugin. This means said application requires that an X Server is up and running before the QApplication is created. If we want said application to connect to an Xwayland server we need to be able to create the Wayland server AND the Xwayland server before creating the QApplication. The solution is to only create the socket notifier if the QCoreApplication exists. For the case that it doesn't exist an additional method is added which needs to be called once the QCoreApplication got created. In addition a manual event dispatch method is added which allows to block for events when we don't have a QSocketNotifier set up yet. --- src/wayland/display.cpp | 42 ++++++++++++++++++++++++++++++++--------- src/wayland/display.h | 16 ++++++++++++++++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index 6332a562d7..350395f441 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -43,6 +43,7 @@ public: Private(Display *q); void flush(); void setRunning(bool running); + void installSocketNotifier(); wl_display *display = nullptr; wl_event_loop *loop = nullptr; @@ -59,11 +60,26 @@ Display::Private::Private(Display *q) { } +void Display::Private::installSocketNotifier() +{ + if (!QCoreApplication::instance()) { + return; + } + int fd = wl_event_loop_get_fd(loop); + if (fd == -1) { + qWarning() << "Did not get the file descriptor for the event loop"; + return; + } + QSocketNotifier *m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read, q); + QObject::connect(m_notifier, &QSocketNotifier::activated, q, [this] { flush(); } ); + QObject::connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, q, [this] { flush(); }); + setRunning(true); +} + Display::Display(QObject *parent) : QObject(parent) , d(new Private(this)) { - connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, [this] { d->flush(); }); } Display::~Display() @@ -106,14 +122,22 @@ void Display::start() } d->loop = wl_display_get_event_loop(d->display); - int fd = wl_event_loop_get_fd(d->loop); - if (fd == -1) { - qWarning() << "Did not get the file descriptor for the event loop"; - return; - } - QSocketNotifier *m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(m_notifier, &QSocketNotifier::activated, this, [this] { d->flush(); } ); - d->setRunning(true); + d->installSocketNotifier(); +} + +void Display::startLoop() +{ + Q_ASSERT(!d->running); + Q_ASSERT(d->display); + d->installSocketNotifier(); +} + +void Display::dispatchEvents(int msecTimeout) +{ + Q_ASSERT(!d->running); + Q_ASSERT(d->display); + wl_event_loop_dispatch(d->loop, msecTimeout); + wl_display_flush_clients(d->display); } void Display::terminate() diff --git a/src/wayland/display.h b/src/wayland/display.h index 7873ed92d1..36b8d5d836 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -57,6 +57,22 @@ public: void start(); void terminate(); + /** + * Starts the event loop for the server socket. + * This method should only be used if start() is used before creating the + * QCoreApplication. In that case start() cannot fully setup the event processing + * and the loop needs to be started after the QCoreApplication got created. + * @see start + * @see dispatchEvents + **/ + void startLoop(); + /** + * Dispatches pending events in a blocking way. May only be used if the Display is + * created and started before the QCoreApplication is created. Once the QCoreApplication + * is created and the event loop is started this method may no longer be invoked. + * @see startLoop + **/ + void dispatchEvents(int msecTimeout = -1); operator wl_display*(); operator wl_display*() const;