Difference between revisions of "TDE DBus Tutorial"

From Trinity Desktop Project Wiki
Jump to navigation Jump to search
imported>Deloptes
(updated to match the status of dbus-1-tqt)
(Better article formatting + added to category Developers)
 
Line 1: Line 1:
  +
[[Category:Developers]]
=Introduction=
 
   
This is a brief introduction on auto-generated DBus interfaces and proxies and their use in TDE.
+
This is a brief introduction on '''auto-generated DBus interfaces and proxies''' and their use in TDE.
   
 
I hope it will save many people time and headache.
 
I hope it will save many people time and headache.
Some more information can be found in the documentation of package dbus-1-tqt.
+
Some more information can be found in the documentation of package <tt>dbus-1-tqt</tt>.
   
  +
All the examples are based on the example in <tt>dbus-1-tqt</tt> for a service providing method <code>ListSorter</code> and for such a client.
The examples were moved to [https://mirror.git.trinitydesktop.org/gitea/deloptes/dbus-1-tqt-example dbus-1-tqt-example]
 
   
  +
__TOC__
All the examples are based on the example in dbus-1-tqt for a service providing method “ListSorter” and for such a client.
 
   
=Create DBus Interface=
+
== Create DBus Interface ==
   
 
To create a DBus interface we need first a definition of the interface. More information on the interface type and signatures can be found in [https://dbus.freedesktop.org/doc/dbus-tutorial.html|the official dbus tutorial]
 
To create a DBus interface we need first a definition of the interface. More information on the interface type and signatures can be found in [https://dbus.freedesktop.org/doc/dbus-tutorial.html|the official dbus tutorial]
   
The definition of the interface is a xml file. We take as example a file describing "org.example.Service" that has one method "ListSorter".
+
The definition of the interface is a XML file. We take as example a file describing <code>org.example.Service</code> that has one method <code>ListSorter</code>.
 
The generated code will automatically include the Introspection interface and we will see how we can create a service to handle both interfaces.
 
The generated code will automatically include the Introspection interface and we will see how we can create a service to handle both interfaces.
   
  +
<syntaxhighlight lang="xml">
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
 
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/example/Service">
+
<node name="/org/example/Service">
<interface name="org.example.Service">
+
<interface name="org.example.Service">
<method name="ListSorter">
+
<method name="ListSorter">
<arg name="input" type="as" direction="in" />
+
<arg name="input" type="as" direction="in" />
<arg name="output" type="as" direction="out" />
+
<arg name="output" type="as" direction="out" />
</method>
+
</method>
</interface>
+
</interface>
</node>
+
</node>
  +
</syntaxhighlight>
   
=Generate the code=
+
== Generate the code ==
   
 
To generate the TQt C++ classes we use dbusxml2qt3
 
To generate the TQt C++ classes we use dbusxml2qt3
   
  +
<syntaxhighlight lang="shell-session">
$ dbusxml2qt3 sortexample.xml
 
  +
$ dbusxml2qt3 sortexample.xml
ClassGenerator: processing interface 'org.example.Service'
 
  +
ClassGenerator: processing interface 'org.example.Service'
Generating org.freedesktop.DBus.Introspectable on demand
 
  +
Generating org.freedesktop.DBus.Introspectable on demand
  +
</syntaxhighlight>
   
 
in the second step generate the proxy with unique namespace to fit your application
 
in the second step generate the proxy with unique namespace to fit your application
   
  +
<syntaxhighlight lang="shell-session">
$/usr/bin/dbusxml2qt3 sortexample.xml
 
  +
$ /usr/bin/dbusxml2qt3 sortexample.xml
  +
</syntaxhighlight>
   
 
the result is
 
the result is
   
  +
<syntaxhighlight lang="shell">
$ ls -1
 
  +
$ ls -1
dbusbaseNode.cpp
 
dbusbaseNode.h
+
dbusbaseNode.cpp
  +
dbusbaseNode.h
introspectableInterface.cpp
 
introspectableInterface.h
+
introspectableInterface.cpp
  +
introspectableInterface.h
serviceInterface.cpp
 
serviceInterface.h
+
serviceInterface.cpp
  +
serviceInterface.h
serviceNode.cpp
 
serviceNode.h
+
serviceNode.cpp
  +
serviceNode.h
serviceProxy.cpp
 
serviceProxy.h
+
serviceProxy.cpp
  +
serviceProxy.h
sortexample.xml
 
  +
sortexample.xml
  +
</syntaxhighlight>
   
=Implement the Service=
+
== Implement the Service ==
   
 
Now we can create our own service using the interface use the proxy as shown below.
 
Now we can create our own service using the interface use the proxy as shown below.
   
==testservice.h==
+
=== testservice.h ===
   
  +
<syntaxhighlight lang="cpp-qt">
#include <tqdbusconnection.h>
 
#include <tqdbusobject.h>
+
#include <tqdbusconnection.h>
#include <tqmap.h>
+
#include <tqdbusobject.h>
#include "serviceInterface.h"
+
#include <tqmap.h>
#include "serviceNode.h"
+
#include "serviceInterface.h"
  +
#include "serviceNode.h"
   
class Interface1 : public org::example::ServiceInterface
+
class Interface1 : public org::example::ServiceInterface
  +
{
{
 
public:
+
public:
Interface1(TQT_DBusConnection&);
+
Interface1(TQT_DBusConnection&);
virtual ~Interface1();
+
virtual ~Interface1();
protected: // implement methods
+
protected: // implement methods
virtual bool ListSorter(const TQStringList& input, TQStringList& output, TQT_DBusError& error);
+
virtual bool ListSorter(const TQStringList& input, TQStringList& output, TQT_DBusError& error);
protected: // implement sending replies
+
protected: // implement sending replies
virtual void handleMethodReply(const TQT_DBusMessage& reply);
+
virtual void handleMethodReply(const TQT_DBusMessage& reply);
private:
+
private:
TQT_DBusConnection *m_connection;
+
TQT_DBusConnection *m_connection;
};
+
};
   
class MultiInterfaceService : public org::example::ServiceNode
+
class MultiInterfaceService : public org::example::ServiceNode
  +
{
{
 
public:
+
public:
MultiInterfaceService(TQT_DBusConnection&);
+
MultiInterfaceService(TQT_DBusConnection&);
~MultiInterfaceService();
+
~MultiInterfaceService();
protected:
+
protected:
virtual TQT_DBusObjectBase* createInterface(const TQString&);
+
virtual TQT_DBusObjectBase* createInterface(const TQString&);
private:
+
private:
TQMap<TQString, TQT_DBusObjectBase*> m_interfaces;
+
TQMap<TQString, TQT_DBusObjectBase*> m_interfaces;
TQT_DBusConnection m_connection;
+
TQT_DBusConnection m_connection;
};
+
};
  +
</syntaxhighlight>
   
==testservice.cpp==
+
=== testservice.cpp ===
   
  +
<syntaxhighlight lang="cpp-qt">
#include <kdebug.h>
 
  +
#include <kdebug.h>
   
// TQt includes
+
// TQt includes
#include <tqdom.h>
+
#include <tqdom.h>
#include <tqstring.h>
+
#include <tqstring.h>
#include <tqstringlist.h>
+
#include <tqstringlist.h>
#include <tqdbuserror.h>
+
#include <tqdbuserror.h>
#include <tqdbusmessage.h>
+
#include <tqdbusmessage.h>
#include <tqdbusdatalist.h>
+
#include <tqdbusdatalist.h>
  +
#include "testservice.h"
   
  +
Interface1::Interface1(TQT_DBusConnection &conn)
#include "testservice.h"
 
  +
: m_connection(&conn)
  +
{
  +
kdDebug() << k_funcinfo << endl;
  +
}
  +
Interface1::~Interface1(){
  +
kdDebug() << k_funcinfo << endl;
  +
}
   
Interface1::Interface1(TQT_DBusConnection &conn)
+
void Interface1::handleMethodReply(const TQT_DBusMessage& reply) {
  +
kdDebug() << k_funcinfo << endl;
: m_connection(&conn)
 
{
+
// do something
  +
m_connection->send(reply);
kdDebug() << k_funcinfo << endl;
 
  +
}
}
 
Interface1::~Interface1(){
 
kdDebug() << k_funcinfo << endl;
 
}
 
   
void Interface1::handleMethodReply(const TQT_DBusMessage& reply) {
+
bool Interface1::ListSorter(const TQStringList& input, TQStringList& output, TQT_DBusError& error) {
kdDebug() << k_funcinfo << endl;
+
kdDebug() << k_funcinfo << endl;
  +
output = input;
// do something
 
m_connection->send(reply);
+
output.sort();
}
+
return true;
  +
}
   
  +
MultiInterfaceService::MultiInterfaceService(TQT_DBusConnection &connection )
bool Interface1::ListSorter(const TQStringList& input, TQStringList& output, TQT_DBusError& error) {
 
  +
: org::example::ServiceNode(), m_connection(connection)
kdDebug() << k_funcinfo << endl;
 
  +
{
output = input;
 
  +
kdDebug() << k_funcinfo << endl;
output.sort();
 
  +
m_interfaces.insert("org.freedesktop.DBus.Introspectable", this);
return true;
 
  +
m_interfaces.insert("org.example.Service", new Interface1(m_connection));
}
 
  +
registerObject(m_connection,"/");
  +
}
   
MultiInterfaceService::MultiInterfaceService(TQT_DBusConnection &connection )
+
MultiInterfaceService::~MultiInterfaceService(){
  +
kdDebug() << k_funcinfo << endl;
: org::example::ServiceNode(), m_connection(connection)
 
  +
}
{
 
kdDebug() << k_funcinfo << endl;
 
m_interfaces.insert("org.freedesktop.DBus.Introspectable", this);
 
m_interfaces.insert("org.example.Service", new Interface1(m_connection));
 
registerObject(m_connection,"/");
 
}
 
   
MultiInterfaceService::~MultiInterfaceService(){
+
TQT_DBusObjectBase* MultiInterfaceService::createInterface(const TQString& interfaceName)
  +
{
kdDebug() << k_funcinfo << endl;
 
  +
kdDebug() << k_funcinfo << endl;
}
 
  +
kdDebug() << "Interface Name: " << interfaceName << endl;
  +
return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
  +
}
  +
</syntaxhighlight>
   
  +
=== tqdbusexample.cpp ===
TQT_DBusObjectBase* MultiInterfaceService::createInterface(const TQString& interfaceName)
 
{
 
kdDebug() << k_funcinfo << endl;
 
kdDebug() << "Interface Name: " << interfaceName << endl;
 
return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
 
}
 
   
  +
<syntaxhighlight lang="cpp-qt">
==tqdbusexample.cpp==
 
  +
#include "testservice.h"
  +
#include <tqapplication.h>
  +
#include <tqdbusconnection.h>
   
  +
int main(int argc, char** argv)
#include "testservice.h"
 
  +
{
#include <tqapplication.h>
 
  +
TQApplication app(argc, argv, false);
#include <tqdbusconnection.h>
 
  +
TQT_DBusConnection connection = TQT_DBusConnection::sessionBus();
  +
// TQT_DBusConnection connection = TQT_DBusConnection::systemBus();
  +
if (!connection.isConnected())
  +
tqFatal("Cannot connect to session bus");
   
  +
// try to get a specific service name
int main(int argc, char** argv)
 
  +
if (!connection.requestName("org.example.Service"))
 
{
 
{
  +
tqWarning("Requesting name 'org.example.Service' failed. "
TQApplication app(argc, argv, false);
 
  +
"Will only be addressable through unique name '%s'",
TQT_DBusConnection connection = TQT_DBusConnection::sessionBus();
 
// TQT_DBusConnection connection = TQT_DBusConnection::systemBus();
 
if (!connection.isConnected())
 
tqFatal("Cannot connect to session bus");
 
// try to get a specific service name
 
if (!connection.requestName("org.example.Service"))
 
{
 
tqWarning("Requesting name 'org.example.Service' failed. "
 
"Will only be addressable through unique name '%s'",
 
 
connection.uniqueName().local8Bit().data());
 
connection.uniqueName().local8Bit().data());
}
 
else
 
{
 
tqDebug("Requesting name 'org.example.Service' successfull");
 
}
 
MultiInterfaceService service(connection);
 
 
return app.exec();
 
 
}
 
}
  +
else
  +
{
  +
tqDebug("Requesting name 'org.example.Service' successfull");
  +
}
  +
MultiInterfaceService service(connection);
   
  +
return app.exec();
==buildtqdbusexample.sh==
 
  +
}
  +
</syntaxhighlight>
   
  +
=== buildtqdbusexample.sh ===
/usr/bin/g++ -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time \
 
-D_FORTIFY_SOURCE=2 -DQT_NO_ASCII_CAST -DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT \
 
-DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT -D_REENTRANT -include tqt.h -I/usr/include/tqt3 \
 
-I/opt/trinity/include/ -I/usr/include/dbus-1-tqt -I/usr/include/tqt -I -DQT_NO_ASCII_CAST \
 
-DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT \
 
-D_REENTRANT -include tqt.h -g -Wl,-z,relro tqdbusexample.cpp testservice.cpp \
 
serviceNode.cpp introspectableInterface.cpp serviceInterface.cpp \
 
-o tqdbusexample -ldbus-1-tqt \
 
/opt/trinity/lib/libtdeparts.so.2.1.0 /opt/trinity/lib/libtdeio.so.14.0.0 \
 
/opt/trinity/lib/libtdecore.so.14.0.0 -ltqt -ltqt-mt -lXrender -lX11 -lc \
 
/usr/lib/x86_64-linux-gnu/libz.so -lidn -lXcomposite -lICE -lSM -lutil -lr -lacl -lattr -ltqui
 
   
  +
{{Box
  +
|caption=Warning! Unflexible code!
  +
|text=This command contains paths which may differ from system to system. You had better use a build system (e.g. CMake) for serious development!
  +
}}
   
  +
<syntaxhighlight lang="bash">
=Using a Proxy=
 
  +
/usr/bin/g++ -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time \
  +
-D_FORTIFY_SOURCE=2 -DQT_NO_ASCII_CAST -DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT \
  +
-DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT -D_REENTRANT -include tqt.h -I/usr/include/tqt3 \
  +
-I/opt/trinity/include/ -I/usr/include/dbus-1-tqt -I/usr/include/tqt -I -DQT_NO_ASCII_CAST \
  +
-DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT \
  +
-D_REENTRANT -include tqt.h -g -Wl,-z,relro tqdbusexample.cpp testservice.cpp \
  +
serviceNode.cpp introspectableInterface.cpp serviceInterface.cpp \
  +
-o tqdbusexample -ldbus-1-tqt \
  +
/opt/trinity/lib/libtdeparts.so.2.1.0 /opt/trinity/lib/libtdeio.so.14.0.0 \
  +
/opt/trinity/lib/libtdecore.so.14.0.0 -ltqt -ltqt-mt -lXrender -lX11 -lc \
  +
/usr/lib/x86_64-linux-gnu/libz.so -lidn -lXcomposite -lICE -lSM -lutil -lr -lacl -lattr -ltqui
  +
</syntaxhighlight>
  +
  +
== Using a Proxy ==
   
 
We will use the service from our first example and implement a proxy to utilize the service.
 
We will use the service from our first example and implement a proxy to utilize the service.
   
==tqdbusproxy.cpp==
+
=== tqdbusproxy.cpp ===
   
  +
<syntaxhighlight lang="cpp-qt">
#include <tqstringlist.h>
 
#include <tqdbusconnection.h>
+
#include <tqstringlist.h>
#include "serviceProxy.h"
+
#include <tqdbusconnection.h>
  +
#include "serviceProxy.h"
   
int main(int argc, char** argv)
+
int main(int argc, char** argv)
  +
{
{
 
  +
TQT_DBusConnection connection = TQT_DBusConnection::sessionBus();
  +
// TQT_DBusConnection connection = TQT_DBusConnection::systemBus();
  +
if (!connection.isConnected())
  +
tqFatal("Cannot connect to session bus");
   
  +
org::example::ServiceProxy serviceProxy("org.example.Service", "/");
TQT_DBusConnection connection = TQT_DBusConnection::sessionBus();
 
// TQT_DBusConnection connection = TQT_DBusConnection::systemBus();
 
if (!connection.isConnected())
 
tqFatal("Cannot connect to session bus");
 
   
org::example::ServiceProxy serviceProxy("org.example.Service", "/");
+
serviceProxy.setConnection(connection);
   
  +
TQStringList list;
serviceProxy.setConnection(connection);
 
  +
list << "D" << "C" << "B" << "A";
   
  +
tqWarning("OUTPUT BEFORE SORT");
TQStringList list;
 
  +
for (TQStringList::iterator it= list.begin(); it != list.end(); ++it) {
list << "D" << "C" << "B" << "A";
 
  +
tqWarning("\t%s",(*it).utf8().data());
  +
}
   
  +
TQStringList data;
tqWarning("OUTPUT BEFORE SORT");
 
  +
TQT_DBusError error;
for (TQStringList::iterator it= list.begin(); it != list.end(); ++it) {
 
  +
if (!serviceProxy.ListSorter(list,data,error)) {
tqWarning("\t%s",(*it).utf8().data());
 
  +
tqFatal("'org.example.Service.ListSorter' failed. ");
  +
}
  +
else {
  +
tqWarning("OUTPUT AFTER SORT");
  +
for (TQStringList::iterator it = data.begin(); it != data.end(); ++it) {
  +
tqWarning("\t%s",(*it).utf8().data());
 
}
 
}
 
TQStringList data;
 
TQT_DBusError error;
 
if (!serviceProxy.ListSorter(list,data,error)) {
 
tqFatal("'org.example.Service.ListSorter' failed. ");
 
}
 
else {
 
tqWarning("OUTPUT AFTER SORT");
 
for (TQStringList::iterator it = data.begin(); it != data.end(); ++it) {
 
tqWarning("\t%s",(*it).utf8().data());
 
}
 
}
 
 
return 0;
 
 
}
 
}
   
  +
return 0;
==buildtqdbusproxy.sh==
 
  +
}
 
  +
</syntaxhighlight>
tmoc serviceProxy.h -o serviceProxy.moc
 
/usr/bin/g++ -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time \
 
-D_FORTIFY_SOURCE=2 -DQT_NO_ASCII_CAST -DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT \
 
-DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT -D_REENTRANT -include tqt.h -I/usr/include/tqt3 \
 
-I/opt/trinity/include/ -I/usr/include/dbus-1-tqt -I/usr/include/tqt -I -DQT_NO_ASCII_CAST \
 
-DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT \
 
-D_REENTRANT -include tqt.h -g -Wl,-z,relro tqdbusproxy.cpp serviceProxy.cpp \
 
-o tqdbusproxy -ldbus-1-tqt \
 
/opt/trinity/lib/libtdeparts.so.2.1.0 /opt/trinity/lib/libtdeio.so.14.0.0 \
 
/opt/trinity/lib/libtdecore.so.14.0.0 -ltqt -ltqt-mt -lXrender -lX11 -lc \
 
/usr/lib/x86_64-linux-gnu/libz.so -lidn -lXcomposite -lICE -lSM -lutil -lr -lacl -lattr -ltqui
 
 
   
  +
=== buildtqdbusproxy.sh ===
=Try it=
 
   
  +
{{Box
== Start the service==
 
  +
|caption=Warning! Unflexible code!
  +
|text=This command contains paths which may differ from system to system. You had better use a build system (e.g. CMake) for serious development!
  +
}}
   
  +
<syntaxhighlight lang="shell">
./tqdbusexample
 
  +
tmoc serviceProxy.h -o serviceProxy.moc
  +
/usr/bin/g++ -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time \
  +
-D_FORTIFY_SOURCE=2 -DQT_NO_ASCII_CAST -DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT \
  +
-DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT -D_REENTRANT -include tqt.h -I/usr/include/tqt3 \
  +
-I/opt/trinity/include/ -I/usr/include/dbus-1-tqt -I/usr/include/tqt -I -DQT_NO_ASCII_CAST \
  +
-DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT \
  +
-D_REENTRANT -include tqt.h -g -Wl,-z,relro tqdbusproxy.cpp serviceProxy.cpp \
  +
-o tqdbusproxy -ldbus-1-tqt \
  +
/opt/trinity/lib/libtdeparts.so.2.1.0 /opt/trinity/lib/libtdeio.so.14.0.0 \
  +
/opt/trinity/lib/libtdecore.so.14.0.0 -ltqt -ltqt-mt -lXrender -lX11 -lc \
  +
/usr/lib/x86_64-linux-gnu/libz.so -lidn -lXcomposite -lICE -lSM -lutil -lr -lacl -lattr -ltqui
  +
</syntaxhighlight>
   
  +
== Try it ==
==Test the service from command line==
 
   
  +
=== Start the service ===
$ dbus-send --print-reply --session --dest=org.example.Service / org.example.Service.ListSorter array:string:"B","A","C"
 
method return time=1571779738.342213 sender=:1.91 -> destination=:1.94 serial=7 reply_serial=2
 
array [
 
string "A"
 
string "B"
 
string "C"
 
]
 
   
  +
<syntaxhighlight lang="shell-session">
  +
$ ./tqdbusexample
  +
</syntaxhighlight>
   
  +
=== Test the service from command line ===
   
  +
<syntaxhighlight lang="shell-session">
==Test the service with proxy client==
 
  +
$ dbus-send --print-reply --session --dest=org.example.Service / org.example.Service.ListSorter array:string:"B","A","C"
  +
method return time=1571779738.342213 sender=:1.91 -> destination=:1.94 serial=7 reply_serial=2
  +
array [
  +
string "A"
  +
string "B"
  +
string "C"
  +
]
  +
</syntaxhighlight>
   
  +
=== Test the service with proxy client ===
$ ./tqdbusproxy
 
[2019/10/22 23:28:11.982] OUTPUT BEFORE SORT
 
[2019/10/22 23:28:11.983] D
 
[2019/10/22 23:28:11.983] C
 
[2019/10/22 23:28:11.983] B
 
[2019/10/22 23:28:11.983] A
 
[2019/10/22 23:28:11.983] OUTPUT AFTER SORT
 
[2019/10/22 23:28:11.983] A
 
[2019/10/22 23:28:11.983] B
 
[2019/10/22 23:28:11.983] C
 
[2019/10/22 23:28:11.983] D
 
   
  +
<syntaxhighlight lang="shell-session">
  +
$ ./tqdbusproxy
  +
[2019/10/22 23:28:11.982] OUTPUT BEFORE SORT
  +
[2019/10/22 23:28:11.983] D
  +
[2019/10/22 23:28:11.983] C
  +
[2019/10/22 23:28:11.983] B
  +
[2019/10/22 23:28:11.983] A
  +
[2019/10/22 23:28:11.983] OUTPUT AFTER SORT
  +
[2019/10/22 23:28:11.983] A
  +
[2019/10/22 23:28:11.983] B
  +
[2019/10/22 23:28:11.983] C
  +
[2019/10/22 23:28:11.983] D
  +
</syntaxhighlight>
   
  +
== External resources ==
=Sample code=
 
   
  +
* [https://mirror.git.trinitydesktop.org/gitea/deloptes/dbus-1-tqt-example Sample code (dbus-1-tqt-example)]
[[:File:Dbus-1-tqt-example.tar.gz|Download sample code here]]
 

Latest revision as of 18:04, 25 August 2021


This is a brief introduction on auto-generated DBus interfaces and proxies and their use in TDE.

I hope it will save many people time and headache. Some more information can be found in the documentation of package dbus-1-tqt.

All the examples are based on the example in dbus-1-tqt for a service providing method ListSorter and for such a client.

Create DBus Interface

To create a DBus interface we need first a definition of the interface. More information on the interface type and signatures can be found in official dbus tutorial

The definition of the interface is a XML file. We take as example a file describing org.example.Service that has one method ListSorter. The generated code will automatically include the Introspection interface and we will see how we can create a service to handle both interfaces.

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/example/Service">
    <interface name="org.example.Service">
        <method name="ListSorter">
            <arg name="input" type="as" direction="in" />
            <arg name="output" type="as" direction="out" />
        </method>
    </interface>
</node>

Generate the code

To generate the TQt C++ classes we use dbusxml2qt3

$ dbusxml2qt3 sortexample.xml
ClassGenerator: processing interface 'org.example.Service'
Generating org.freedesktop.DBus.Introspectable on demand

in the second step generate the proxy with unique namespace to fit your application

$ /usr/bin/dbusxml2qt3 sortexample.xml

the result is

$ ls -1
dbusbaseNode.cpp
dbusbaseNode.h
introspectableInterface.cpp
introspectableInterface.h
serviceInterface.cpp
serviceInterface.h
serviceNode.cpp
serviceNode.h
serviceProxy.cpp
serviceProxy.h
sortexample.xml

Implement the Service

Now we can create our own service using the interface use the proxy as shown below.

testservice.h

#include <tqdbusconnection.h>
#include <tqdbusobject.h>
#include <tqmap.h>
#include "serviceInterface.h"
#include "serviceNode.h"

class Interface1 : public org::example::ServiceInterface
{
public:
    Interface1(TQT_DBusConnection&);
    virtual ~Interface1();
protected: // implement methods
    virtual bool ListSorter(const TQStringList& input, TQStringList& output, TQT_DBusError& error);
protected: // implement sending replies
    virtual void handleMethodReply(const TQT_DBusMessage& reply);
private:
    TQT_DBusConnection *m_connection;
};

class MultiInterfaceService : public org::example::ServiceNode
{
public:
    MultiInterfaceService(TQT_DBusConnection&);
    ~MultiInterfaceService();
protected:
    virtual TQT_DBusObjectBase* createInterface(const TQString&);
private:
    TQMap<TQString, TQT_DBusObjectBase*> m_interfaces;
    TQT_DBusConnection m_connection;
};

testservice.cpp

#include <kdebug.h>

// TQt includes
#include <tqdom.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqdbuserror.h>
#include <tqdbusmessage.h>
#include <tqdbusdatalist.h>
#include "testservice.h"

Interface1::Interface1(TQT_DBusConnection &conn)
   : m_connection(&conn)
{
    kdDebug() << k_funcinfo << endl;
}
Interface1::~Interface1(){
    kdDebug() << k_funcinfo << endl;
}

void Interface1::handleMethodReply(const TQT_DBusMessage& reply) {
    kdDebug() << k_funcinfo << endl;
    // do something
    m_connection->send(reply);
}

bool Interface1::ListSorter(const TQStringList& input, TQStringList& output, TQT_DBusError& error) {
    kdDebug() << k_funcinfo << endl;
    output = input;
    output.sort();
    return true;
}

MultiInterfaceService::MultiInterfaceService(TQT_DBusConnection &connection )
    : org::example::ServiceNode(), m_connection(connection)
{
    kdDebug() << k_funcinfo << endl;
    m_interfaces.insert("org.freedesktop.DBus.Introspectable", this);
    m_interfaces.insert("org.example.Service", new Interface1(m_connection));
    registerObject(m_connection,"/");
}

MultiInterfaceService::~MultiInterfaceService(){
    kdDebug() << k_funcinfo << endl;
}

TQT_DBusObjectBase* MultiInterfaceService::createInterface(const TQString& interfaceName)
{
    kdDebug() << k_funcinfo << endl;
    kdDebug() << "Interface Name: " << interfaceName << endl;
    return (TQT_DBusObjectBase*) m_interfaces[interfaceName];
}

tqdbusexample.cpp

#include "testservice.h"
#include <tqapplication.h>
#include <tqdbusconnection.h>

int main(int argc, char** argv)
{
    TQApplication app(argc, argv, false);
    TQT_DBusConnection connection = TQT_DBusConnection::sessionBus();
//  TQT_DBusConnection connection = TQT_DBusConnection::systemBus();
    if (!connection.isConnected())
        tqFatal("Cannot connect to session bus");

    // try to get a specific service name
    if (!connection.requestName("org.example.Service"))
    {
        tqWarning("Requesting name 'org.example.Service' failed. "
               "Will only be addressable through unique name '%s'",
                connection.uniqueName().local8Bit().data());
    }
    else
    {
        tqDebug("Requesting name 'org.example.Service' successfull");
    }
    MultiInterfaceService service(connection);

    return app.exec();
}

buildtqdbusexample.sh

Gear.png
Warning! Unflexible code!
This command contains paths which may differ from system to system. You had better use a build system (e.g. CMake) for serious development!
/usr/bin/g++   -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time \
-D_FORTIFY_SOURCE=2  -DQT_NO_ASCII_CAST -DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT \
-DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT -D_REENTRANT -include tqt.h -I/usr/include/tqt3 \
-I/opt/trinity/include/ -I/usr/include/dbus-1-tqt -I/usr/include/tqt -I -DQT_NO_ASCII_CAST \
-DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT \
-D_REENTRANT -include tqt.h -g  -Wl,-z,relro tqdbusexample.cpp  testservice.cpp \
serviceNode.cpp introspectableInterface.cpp serviceInterface.cpp \
-o tqdbusexample -ldbus-1-tqt \
/opt/trinity/lib/libtdeparts.so.2.1.0 /opt/trinity/lib/libtdeio.so.14.0.0 \
/opt/trinity/lib/libtdecore.so.14.0.0 -ltqt -ltqt-mt -lXrender -lX11 -lc \
/usr/lib/x86_64-linux-gnu/libz.so -lidn -lXcomposite -lICE -lSM -lutil -lr -lacl -lattr -ltqui

Using a Proxy

We will use the service from our first example and implement a proxy to utilize the service.

tqdbusproxy.cpp

#include <tqstringlist.h>
#include <tqdbusconnection.h>
#include "serviceProxy.h"

int main(int argc, char** argv)
{
    TQT_DBusConnection connection = TQT_DBusConnection::sessionBus();
//  TQT_DBusConnection connection = TQT_DBusConnection::systemBus();
    if (!connection.isConnected())
        tqFatal("Cannot connect to session bus");

    org::example::ServiceProxy serviceProxy("org.example.Service", "/");

    serviceProxy.setConnection(connection);

    TQStringList list;
    list << "D" << "C" << "B" << "A";

    tqWarning("OUTPUT BEFORE SORT");
    for (TQStringList::iterator it= list.begin(); it != list.end(); ++it) {
        tqWarning("\t%s",(*it).utf8().data());
    }

    TQStringList data;
    TQT_DBusError error;
    if (!serviceProxy.ListSorter(list,data,error)) {
        tqFatal("'org.example.Service.ListSorter' failed. ");
    }
    else {
        tqWarning("OUTPUT AFTER SORT");
        for (TQStringList::iterator it = data.begin(); it != data.end(); ++it) {
            tqWarning("\t%s",(*it).utf8().data());
        }
    }

    return 0;
}

buildtqdbusproxy.sh

Gear.png
Warning! Unflexible code!
This command contains paths which may differ from system to system. You had better use a build system (e.g. CMake) for serious development!
tmoc serviceProxy.h -o serviceProxy.moc
/usr/bin/g++   -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time \
-D_FORTIFY_SOURCE=2  -DQT_NO_ASCII_CAST -DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT \
-DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT -D_REENTRANT -include tqt.h -I/usr/include/tqt3 \
-I/opt/trinity/include/ -I/usr/include/dbus-1-tqt -I/usr/include/tqt -I -DQT_NO_ASCII_CAST \
-DQT_CLEAN_NAMESPACE -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION -DQT_THREAD_SUPPORT \
-D_REENTRANT -include tqt.h -g  -Wl,-z,relro tqdbusproxy.cpp serviceProxy.cpp \
-o tqdbusproxy -ldbus-1-tqt \
/opt/trinity/lib/libtdeparts.so.2.1.0 /opt/trinity/lib/libtdeio.so.14.0.0 \
/opt/trinity/lib/libtdecore.so.14.0.0 -ltqt -ltqt-mt -lXrender -lX11 -lc \
/usr/lib/x86_64-linux-gnu/libz.so -lidn -lXcomposite -lICE -lSM -lutil -lr -lacl -lattr -ltqui

Try it

Start the service

$ ./tqdbusexample

Test the service from command line

$ dbus-send --print-reply  --session --dest=org.example.Service / org.example.Service.ListSorter array:string:"B","A","C"
method return time=1571779738.342213 sender=:1.91 -> destination=:1.94 serial=7 reply_serial=2
  array [
     string "A"
     string "B"
     string "C"
  ]

Test the service with proxy client

$ ./tqdbusproxy
[2019/10/22 23:28:11.982] OUTPUT BEFORE SORT
[2019/10/22 23:28:11.983]       D
[2019/10/22 23:28:11.983]       C
[2019/10/22 23:28:11.983]       B
[2019/10/22 23:28:11.983]       A
[2019/10/22 23:28:11.983] OUTPUT AFTER SORT
[2019/10/22 23:28:11.983]       A
[2019/10/22 23:28:11.983]       B
[2019/10/22 23:28:11.983]       C
[2019/10/22 23:28:11.983]       D

External resources