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.
This commit is contained in:
Martin Gräßlin 2014-11-07 11:41:37 +01:00
parent 376a2ffac9
commit 9d5d8d0871
2 changed files with 49 additions and 9 deletions

View file

@ -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;
d->installSocketNotifier();
}
QSocketNotifier *m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(m_notifier, &QSocketNotifier::activated, this, [this] { d->flush(); } );
d->setRunning(true);
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()

View file

@ -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;