Pergunta

Meu objetivo é criar uma biblioteca usando o Ligações DBus do Qt.

Tentei criar um aplicativo Qt sem iniciar o QEventLoop (fornecida pelo QCoreApplication class) no thread principal.

Aqui está um exemplo de aplicativo minimalista, funcionando bem usando a versão QT-4.6.2, mas bloqueando a introspecção usando QT-4.8 ou superior.

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

principal.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());
}

Como você pode ver no main.cpp arquivo, app.exec() é comentado, mas faz com que o aplicativo funcione bem no QT-4.8 ou versões superiores (5.3.0).

Minha pergunta é a seguinte:É possível usar as ligações DBus do Qt chamando app.exec() em um outro tópico do que o principal, no Qt-4.8 ou 5.3?

Foi útil?

Solução

Fundo:Existe uma aula particular chamada QDBusConnectionPrivate que herda de QObject e lida com todas as redes.Infelizmente, se você olhar qdbusconnection.cpp:1116 você verá que o Qt codifica o moveToThread para QCoreApplication::instance().

Você provavelmente deve enviar uma solicitação de aprimoramento para permitir que o usuário crie um QDBusConnection que use um thread ou loop de eventos especificado pelo usuário. Veja a atualização abaixo.

Enquanto isso, se você se sentir confortável fazendo algumas coisas perigosas, você pode hackear você mesmo criando seu próprio QDbusConnection subclasse (chamei a minha SpecializedDBusConnection) que leva QThread como um terceiro argumento de onde você quer que o QDbusConnectionPrivate instância para a qual será movida.Em seguida, use essa classe para criar a conexão em vez do padrão QDbusConnection::sessionBus().

Como se trata de algumas classes privadas, é necessária a inclusão de alguns arquivos de cabeçalho privados (observados no código abaixo) que, por sua vez, tentarão incluir vários cabeçalhos da biblioteca dbus, o que exigirá a modificação de INCLUDEPATH do projeto para incluir o caminho de inclusão da biblioteca dbus.

Verifiquei que isso funciona no Qt 5.3.0 e no Qt 4.8.6.

Atualizar: Em Qt 5.6, QtDBus foi refatorado para usar threads para processamento de mensagens recebidas/saídas;chega de bloqueio do thread principal!

DBusHandler.hpp

#pragma once
#include <iostream>
#include <QtCore/QThread>
#include <QtCore/QtCore>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnectionInterface>

#include "/path/to/Qt5.3.0/5.3/Src/qtbase/src/dbus/qdbusconnection_p.h"

class SpecializedDBusConnection : public QDBusConnection {
    const char *ownName;
public:
    inline SpecializedDBusConnection(BusType type, const char *name, QThread *thread)
        : QDBusConnection(connectToBus(type, QString::fromLatin1(name))), ownName(name)
    {
        if (QDBusConnectionPrivate::d(*this)) {
            QDBusConnectionPrivate::d(*this)->moveToThread(thread);
        }
    }

    inline ~SpecializedDBusConnection()
    { disconnectFromBus(QString::fromLatin1(ownName)); }
};

class DBusHandler : public QThread
{
    Q_OBJECT;

private:     
    void run(void)
    {
        QDBusConnection connection = SpecializedDBusConnection(QDBusConnection::SessionBus, "qt_default_session_bus", this);

        connection.registerService("my.qdbus.example");
        connection.registerObject("/", this, QDBusConnection::ExportAllSlots);

        exec();
    }
[snip]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top