- PVSM.RU - https://www.pvsm.ru -
Предыдущая [1] часть оставляла мрачные прогнозы, но все оказалось гораздо, гораздо, гораздо лучше.
Итак, спсаибо хабражителю он обратил внимание на то, что у QDbusAbstractAdaptor должен быть родитель. Для меня это оказалось новостью, т.к. я сильно привык, что родителя может и не быть. Может это убережет еще кого-то от подобного ляпа.
Вдобавок мое незнание патернов, есть такой патен «Адаптер». Так вот QAbstractAdaptor собственно это он и есть. С учетом вышесказанного и замечания доки, что этот класс должен быть легковесным пример, действительно проясняющий подход либы должен быть таким:
Проект Pong:
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusError>
#include <QDebug>
#include "Pong.h"
#include "../serviceNameAndProperty.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDBusConnection connection = QDBusConnection::sessionBus();
Pong pong;
if( ! connection.registerObject("/", &pong)){
fprintf(stderr, "%sn",
qPrintable("Can't register object"));
exit(1);
}
qDebug()<<"Pong connected to D-bus";
if (!connection.registerService(SERVICE_NAME)) {
fprintf(stderr, "%sn",
qPrintable(QDBusConnection::sessionBus().lastError().message()));
exit(1);
}
qDebug()<<"Test service start";
return a.exec();
}
#ifndef PONG_H
#define PONG_H
#include <QDBusAbstractAdaptor>
#include <QDBusVariant>
#include <QDBusArgument>
#include <QDBusContext>
#include "../serviceNameAndProperty.h"
class Pong;
class PongAdapter : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", BUFFER_NAME)
Q_PROPERTY(QString IMAGE_DATA_SHARED_ID READ imageDataSharedId)
public:
explicit PongAdapter(Pong *parent);
QString imageDataSharedId();
public slots:
TestStructure structureField();
signals:
void callingMe(QString, QString);
private:
Pong * m_parentPong;
};
class Pong : public QObject, public QDBusContext
{
Q_OBJECT
public:
Pong()
{
m_pongAdapter = new PongAdapter(this);
QObject::connect(this, SIGNAL(callingMe(QString,QString)), m_pongAdapter, SIGNAL(callingMe(QString, QString)));
m_imageDataSharedId = "testImageBufferId";
}
public:
QString imageDataSharedId();
TestStructure& structureField();
signals:
void callingMe(QString, QString);
private:
PongAdapter *m_pongAdapter;
QString m_imageDataSharedId;
TestStructure test;
};
#endif // PONG_H>
#include "Pong.h"
#include <QDebug>
#include <QDBusMetaType>
#include <QDBusConnection>
#include <QDBusMessage>
PongAdapter::PongAdapter(Pong *parent) :
QDBusAbstractAdaptor(parent)
{
m_parentPong = parent;
qRegisterMetaType<TestStructure>("TestStructure");
qDBusRegisterMetaType<TestStructure>();
}
QString PongAdapter::imageDataSharedId()
{
return m_parentPong->imageDataSharedId();
}
TestStructure PongAdapter::structureField()
{
return m_parentPong->structureField();
}
QString Pong::imageDataSharedId()
{
return m_imageDataSharedId;
}
TestStructure &Pong::structureField()
{
qDebug()<<"Me calld"<<QDBusConnection::sessionBus().baseService()<<message().service();
emit callingMe(QString("Panic"), QString("Super panic"));
test.str = QString("ku");
test.id =2;
return test;
}
Проект Ping:
#include <stdio.h>
#include <QObject>
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusServiceWatcher>
#include <QDebug>
#include "Ping.h"
#include "../serviceNameAndProperty.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Ping ping;
if (!QDBusConnection::sessionBus().isConnected()) {
fprintf(stderr, "Cannot connect to the D-Bus session bus.n"
"To start it, run:n"
"teval `dbus-launch --auto-syntax`n");
return 1;
}
qDebug()<<"Ping connected to D-bus";
QDBusConnectionInterface *iface = QDBusConnection::sessionBus().interface();
QDBusServiceWatcher watcher;
watcher.setConnection(QDBusConnection::sessionBus());;
watcher.addWatchedService(ping.m_aviableServiceName);
// QObject::connect(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),&ping, SLOT(manageConnection(QString,QString,QString)));
QObject::connect(&watcher, SIGNAL(serviceRegistered(QString)), &ping, SLOT(connectToService(QString)));
QStringList registedServices = iface->registeredServiceNames();
if(registedServices.contains(ping.m_aviableServiceName))
ping.connectToService(ping.m_aviableServiceName);
return a.exec();
}
#ifndef PING_H
#define PING_H
#include <QObject>
#include <QDBusAbstractInterface>
#include <qdbusinterface.h>
class Ping : public QObject
{
Q_OBJECT
public:
explicit Ping(QObject *parent = 0);
public slots:
void manageConnection(const QString &name, const QString &oldVAlue, const QString &newValue);
void connectToService(const QString &name);
void disconnect(const QString &name);
void reacoOnMeCalling(QString message, QString message2);
public:
QString m_aviableServiceName;
private:
QDBusInterface *m_interface;
QString m_interfaceName;
static const QString _propertyName;
};
#endif // PING_H
#include "Ping.h"
#include "../serviceNameAndProperty.h"
#include <QDBusConnectionInterface>
#include <QDebug>
#include <QDBusMetaType>
const QString Ping::_propertyName(QUIOTING(IMAGE_DATA_SHARED_ID));
Ping::Ping(QObject *parent) :
QObject(parent)
{
m_interface = NULL;
m_interfaceName = QString(BUFFER_NAME);
m_aviableServiceName = QString(SERVICE_NAME);
qRegisterMetaType<TestStructure>("TestStructure");
qDBusRegisterMetaType<TestStructure>();
}
void Ping::manageConnection(const QString& name, const QString &oldVAlue, const QString &newValue)
{
Q_UNUSED(oldVAlue)
if(name != m_aviableServiceName)
return;
if(newValue.isEmpty())
disconnect(name);
else
connectToService(name);
}
void Ping::connectToService(const QString &name)
{
if(name != m_aviableServiceName)
return;
qDebug()<<"Connceting";
m_interface = new QDBusInterface(name, "/", m_interfaceName, QDBusConnection::sessionBus(), this);
QObject::connect(m_interface, SIGNAL(callingMe(QString, QString)), this, SLOT(reacoOnMeCalling(QString, QString)));
if(!m_interface->isValid()){
qDebug()<<"Invalid interface"<<m_interface->lastError();
delete m_interface;
m_interface = NULL;
return;
}
qDebug()<<m_interface->interface();
QVariant var("sss");
var = m_interface->property("imageDataSharedId");
qDebug()<<var;
QDBusReply<TestStructure> reply= m_interface->call("structureField");
if(reply.isValid())
{
TestStructure testStructure = reply.value();
qDebug()<<testStructure.id<<testStructure.str;
}
}
void Ping::disconnect(const QString &name)
{
if(name != m_aviableServiceName)
return;
if(name != m_interface->service())
return;
delete m_interface;
m_interface = NULL;
qDebug()<<"Disconnect";
}
void Ping::reacoOnMeCalling(QString message, QString message2)
{
qDebug()<<message<<message2;
}
#pragma once
#include<QMetaType>
#include <QString>
#include <QDBusArgument>
#define SERVICE_NAME "ru.sonarh.dbus.pong"
#define BUFFER_NAME "ru.buffer"
#define IMAGE_DATA_SHARED_ID imageDataSharedId
#define QUIOTING(text) #text
struct TestStructure{
int id;
QString str;
};
Q_DECLARE_METATYPE(TestStructure)
static QDBusArgument& operator <<(QDBusArgument &argument, const TestStructure & arg)
{
argument.beginStructure();
argument<<arg.id<<arg.str;
argument.endStructure();
return argument;
}
static const QDBusArgument& operator >>(const QDBusArgument &argument, TestStructure & arg)
{
argument.beginStructure();
argument>>arg.id>>arg.str;
argument.endStructure();
return argument;
}
Ради целостности представления как пользоваться модулем позволю себе повторение пройденного. Благо повторение — мать учения.
Итак у нас есть класс Pong, мы хотим, его сделать доступным для взаимодействия по D-Bus. Что для этого нужно:
if (!QDBusConnection::sessionBus().isConnected()) {
if (!connection.registerService(SERVICE_NAME)) {
Важно! оно должно содержать хотя бы один разделяющий символ — точку.
QObject::connect(this, SIGNAL(callingMe(QString,QString)), m_pongAdapter, SIGNAL(callingMe(QString, QString)));
Важно! имя интерфейса адаптера, задаваемого в Q_ClASSINFO должно содержать точку.
if( ! connection.registerObject("/", &pong)){
Важно! Этот путь должен содержать хотя бы один разделяющий символ -/
Интересный поворот в этой истории это то, что если мы хотим знать контекст сообщения, которое активировало слот, то нам нужно реальный объект (Pong) отнаследовать от QDbusContext, но при этом, контекстные методы, аля message нужно дергать в адаптере, если мы по-прежнему хотим абстрогироваться от D-Bus и не заполучить головную боль при тестировании. Довольно странный поворот, но пока с неудобствами, им вызванным, я не столкнулся.
И раз уже заговорили о контексте, то нельзя не упомянуть о сердце всего модуля. И сердце это двухкамерное: первая камера — это QDbusMessage т.е. те самые послания которыми обмениваются участники, а вторая камера это их интерпретация в виде QDbusArgument и QDbusReply. Впринципе, послания можно формировать вручную. Например, обращения к property в dbusviwer сделана так:
QDBusMessage message = QDBusMessage::createMethodCall(sig.mService, sig.mPath, QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
QList<QVariant> arguments;
arguments << sig.mInterface << sig.mName;
message.setArguments(arguments);
c.callWithCallback(message, this, SLOT(dumpMessage(QDBusMessage)));
QDBusInterface iface(sig.mService, sig.mPath, sig.mInterface,c);
if( !iface.isValid())
qDebug()<<(QDBusError(iface.lastError()).message());
else
qDebug()<<iface.property(sig.mName.toLatin1().data());
Но гораздо проще доверить формирование послание QDbusArgument. Для это необходимо всего две вещи: реализовать операторы >> <<, если у вас тип не укладывающийся базовые в стандартные Qt:
struct TestStructure{
int id;
QString str;
};
Q_DECLARE_METATYPE(TestStructure)
static QDBusArgument& operator <<(QDBusArgument &argument, const TestStructure & arg)
{
argument.beginStructure();
argument<<arg.id<<arg.str;
argument.endStructure();
return argument;
}
И до первого использования вызвать qDBusRegisterMetaType. И после это трудности заканчиваются: с помощью QDbusInterface вы вызываете нужный метод, если это не void-метод, и возвращаемое значение нам важно и нужно, то используем шаблонный класс QDbusReply.
На этом все, действительно все. Знакомство с модулем закончено, впереди только поле где его надо использовать.
Автор: DancingOnWater
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/38813
Ссылки в тексте:
[1] Предыдущая: http://habrahabr.ru/post/185212/
[2] Источник: http://habrahabr.ru/post/185950/
Нажмите здесь для печати.