My goal is to create a library using the Qt's DBus bindings.
I tried to create a Qt application without launching the QEventLoop
(provided by the QCoreApplication
class) in the main thread.
Here is a minimalistic application sample, working fine using QT-4.6.2 version but blocking on introspection using QT-4.8 or higher.
DBusHandler.hpp
#pragma once
#include <iostream>
#include <QtCore/QThread>
#include <QtCore/QtCore>
#include <QtDBus/QDBusInterface>
class DBusHandler : public QThread
{
Q_OBJECT;
private:
void run(void)
{
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerService("my.qdbus.example");
connection.registerObject("/", this, QDBusConnection::ExportAllSlots);
exec();
}
public:
DBusHandler(void) {}
virtual ~DBusHandler(void) {}
void stop(void)
{
QDBusConnection connection = QDBusConnection::sessionBus();
connection.unregisterObject("/");
connection.unregisterService("my.qdbus.example");
connection.disconnectFromBus(connection.name());
QThread::quit();
}
public slots:
void remoteCall(QByteArray message)
{
std::cout << "Message size: " << message.size() << std::endl;
}
};
main.cpp
#include "DBusHandler.hpp"
int main(int ac, char **av)
{
QCoreApplication app(ac, av);
DBusHandler handler;
handler.moveToThread(&handler);
handler.start();
while (not handler.isRunning());
// app.exec();
sleep(10); // Gives time to call using the command line: "qdbus my.qdbus.example / local.DBusHandler.remoteCall a_message"
handler.stop();
while (handler.isRunning());
}
As you can see in the main.cpp
file, app.exec()
is commented out, but makes the application working fine on QT-4.8 or higher versions (5.3.0).
My question is the following: Is it possible to use the Qt's DBus bindings calling app.exec()
in an other thread than the main one, on Qt-4.8 or 5.3 ?
Background: There is a private class called
QDBusConnectionPrivate
which inherits from QObject and handles all networking. Unfortunately, if you look atqdbusconnection.cpp:1116
you'll see that Qt hard codes themoveToThread
toQCoreApplication::instance()
.You should probably submit an enhancement request to allow the user to create a QDBusConnection that uses a user specified thread or event loop.See update below.In the meantime, if you're comfortable doing some dangerous things, you can hack it in yourself by creating your own
QDbusConnection
subclass (I called mineSpecializedDBusConnection
) that takesQThread
as a third argument of where you want theQDbusConnectionPrivate
instance to be moved to. Then use that class to create the connection instead of the defaultQDbusConnection::sessionBus()
.As this is using some private classes, it requires the inclusion of some private header files (noted in the code below) which in turn will attempt to include various dbus library headers which will necessitate the modifying of INCLUDEPATH of the project to include the dbus library include path.
I've verified this works on Qt 5.3.0 and Qt 4.8.6.
Update: In Qt 5.6, QtDBus was refactored to use threads for incoming/outgoing message processing; no more blocking of the main thread!
DBusHandler.hpp