{"id":26,"date":"2011-03-10T14:01:32","date_gmt":"2011-03-10T14:01:32","guid":{"rendered":"http:\/\/liberty.fdn.fr\/?p=26"},"modified":"2025-08-17T20:12:59","modified_gmt":"2025-08-17T20:12:59","slug":"introduction-a-dbus-avec-qt4","status":"publish","type":"post","link":"http:\/\/renaudguezennec.eu\/index.php\/2011\/03\/10\/introduction-a-dbus-avec-qt4\/","title":{"rendered":"Introduction \u00e0 Dbus avec Qt4"},"content":{"rendered":"<div class=\"article\" lang=\"fr\">\n<h2>Dbus<\/h2>\n<p class=\"readability-styled\">Dbus est un bus syst\u00e8me de messagerie. C&#8217;est un moyen simple pour des applications de communiquer entre elles. En plus de la communication interprocessus, Dbus est aussi un outil aidant au cycle de vie du processus. Il peut vous permettre de n&#8217;autoriser qu&#8217;une seule instance de votre application ou de votre daemon. Il peut vous permettre de d\u00e9marrer votre application ou daemon \u00e0 la demande quand elles sont n\u00e9cessaires. Il est possible d&#8217;\u00e9tablir deux types de connexions: point \u00e0 point ou point d&#8217;acc\u00e8s (daemon central). Gr\u00e2ce au daemon, vos applications peuvent \u00eatre pr\u00e9venues du branchement d&#8217;un nouvel composant mat\u00e9riel. Le bus de session (un par utilisateur connect\u00e9) est le canal g\u00e9n\u00e9rique de communication. Dbus est destin\u00e9 \u00e0 la communication entre application d&#8217;un m\u00eame ordinateur. Il est cependant possible de communiquer par TCP\/IP crypt\u00e9 avec un dossier home partag\u00e9 par NFS. Ce genre d&#8217;usage reste rare et exp\u00e9rimental.<\/p>\n<p>Il est possible d&#8217;utiliser Dbus dans de nombreux langages: C\/C++, python, ruby, perl, java, C#. Je vais me concenter sur l&#8217;impl\u00e9mentation de Dbus dans Qt4, dans cet article.<\/p>\n<\/div>\n<div class=\"article\" lang=\"fr\">\n<p><a name=\"compile\"><\/a><\/p>\n<h2>Dbus dans Qt4<\/h2>\n<p class=\"readability-styled\">Qt4 implement sa propre API Dbus. Le support de Dbus sur windows \u00e9tant en cours (d&#8217;apr\u00e8s le site internet), Qt a \u00e9t\u00e9 sage de regrouper toutes les fonctionnalit\u00e9s dans un module. Pour des environnements linux, il suffit d&#8217;installer la biblioth\u00e8que et \u00e0 l&#8217;\u00e9dition des liens, ajouter<\/p>\n<p><code class=\"filename\">QT += dbus<\/code><\/p>\n<p class=\"readability-styled\">Dans le fichier pro pour inclure le module dbus \u00e0 votre projet.<\/p>\n<p class=\"readability-styled\">Les deux classes importantes sont QDbusMessage et QDbusInterface. La premi\u00e8re permet d&#8217;envoyer facilement un message vers un service Dbus. C&#8217;est un moyen rapide pour communiquer une information vers une application dont vous ne maitrisez rien. Le QBusInterface permet une communication plus transparente, car tous les signaux\/slots de votre application (d&#8217;une classe, pour \u00eatre pr\u00e9cis) seront mis sur Dbus.<\/p>\n<\/div>\n<div class=\"article\" lang=\"fr\">\n<p><a name=\"outils\"><\/a><\/p>\n<h2>Monitorer Dbus<\/h2>\n<p class=\"readability-styled\">Vous ne le savez peut-\u00eatre pas mais votre syst\u00e8me GNU\/Linux (s&#8217;il est assez moderne) utilise probablement DBUS en continue. Pour se donner une id\u00e9e, il existe deux utilitaires assez int\u00e9ressant: dbus-monitor et qdbusviewer.<\/p>\n<p><a href=\"http:\/\/renaudguezennec.eu\/prog\/tutorial\/16\/qdbusviewer.png\" rel=\"lightbox\"><img decoding=\"async\" src=\"http:\/\/renaudguezennec.eu\/prog\/tutorial\/16\/mini_qdbusviewer.png\" alt=\"capture de qdbusviewer\" \/><\/a><\/p>\n<\/div>\n<div class=\"article\" lang=\"fr\">\n<p>&nbsp;<\/p>\n<h2>Connexion \u00e0 un service : Pidgin<\/h2>\n<p class=\"readability-styled\">Nous allons maintenant impl\u00e9ment\u00e9 une solution pour utiliser un service d&#8217;une application. Nous voulons mettre \u00e0 jour la petite phrase de status de pidgin. Ainsi votre logiciel de lecture audio pourra mettre en petite phrase la chanson actuellement jou\u00e9e.<\/p>\n<p class=\"readability-styled\">La premi\u00e8re \u00e9tape est d&#8217;identifi\u00e9 la fonction (et son chemin) qui nous int\u00e9resse. En g\u00e9n\u00e9ral, les logiciels libres fournissent dans leur documentation l&#8217;API dbus qu&#8217;ils offrent. Cependant, l&#8217;outil qdbusviewer vous permet de voir toutes ces informations.<\/p>\n<p class=\"readability-styled\">En terme de code, cela reste tr\u00e8s simple. Vous d\u00e9clarez un message Dbus. Il faut d\u00e9finir les bonnes valeurs: chemin, destinataire, noms..<\/p>\n<\/div>\n<p>[pastacode lang=&#8221;cpp&#8221; message=&#8221;Connexion \u00e0 un service dbus&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221; manual=&#8221;QDBusConnection%20sessionbus%20%3D%20QDBusConnection%3A%3AsessionBus()%3B%0A%0Aif%20(%20!sessionbus.isConnected()%20)%0A%7B%0A%20%20%20%20qDebug()%20%3C%3C%20%22Could%20not%20connect%20to%20session%20bus%22%3B%0A%7D%0A%20%20%20%20QDBusMessage%20m%20%3D%20%0A%20%20%20%20QDBusMessage%3A%3AcreateMethodCall(%22im.pidgin.purple.PurpleService%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%2Fim%2Fpidgin%2Fpurple%2FPurpleObject%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22im.pidgin.purple.PurpleInterface%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22PurpleUtilSetCurrentSong%22)%3B%0A%20%20%20%20QList%3CQVariant%3E%20args%3B%0A%20%20%20%20args%20%3C%3C%20m_p-%3ETitle%20%3C%3C%20m_p-%3EArtist%20%3C%3C%20m_p-%3Ealbum%3B%0A%20%20%20%20m.setArguments(args)%3B%0A%20%20%20%20QDBusMessage%20metadatamsg%20%3D%20sessionbus.call(m)%3B%0A%20%20%20%20if(metadatamsg.type()%20!%3D%20QDBusMessage%3A%3AReplyMessage)%0A%20%20%20%20%20%20%20%20qDebug()%20%3C%3C%20%22Error%20its%20not%20a%20message%20%22%20%3C%3C%20metadatamsg.type()%20%3C%3C%20metadatamsg.errorMessage%20()%3B&#8221;\/]<\/p>\n<div class=\"article\" lang=\"fr\">La premi\u00e8re \u00e9tape est de d\u00e9finir quel bus vous allez utiliser : le sessionBus ou le systembus? Dans notre cas, c&#8217;est le sessionBus. On verifie que tout se passe bien niveau connection au bus. Il convient ensuite de cr\u00e9er un message. Les param\u00e8tres du messages sont les suivants :<\/p>\n<ul>\n<li>Le nom du service (la colonne de gauche de qdbusviewer)<\/li>\n<li>Le chemin vers l&#8217;objet (concat\u00e9nation de tous les noeuds de l&#8217;arbre sauf celui de l&#8217;interface).<\/li>\n<li>Le chemin vers l&#8217;interface (noeud en italique dans qdbusviewer).<\/li>\n<li>Une liste d&#8217;arguments peut \u00eatre pass\u00e9e \u00e0 l&#8217;appel de la m\u00e9thode du service. Dans notre cas, nous passons le titre de la chanson, l&#8217;artiste et le nom de l&#8217;album.<\/li>\n<li>Derni\u00e8re \u00e9tape, appel de la m\u00e9thode suivit d&#8217;une v\u00e9rification d&#8217;erreur.<\/li>\n<\/ul>\n<p>La voie royale pour faire communiquer deux applications via dbus gr\u00e2ce \u00e0 Qt est l&#8217;utilisation des adaptors. Ils traduisent les signaux et slots d&#8217;une classe Qt en message Dbus. C&#8217;est totalement transparent. Pour faire un exemple simple, je vais faire une application qui propose un service &#8220;dbus_example_Service&#8221;, de d\u00e9finition de brigthness et les clients peuvent d\u00e9finir le nouveau de volume. Plusieurs applications peuvent envoyer le volume au service et elles peuvent \u00e9galement recevoir la brightness. Une seule et unique application peut faire office de service. Deux instance de l&#8217;application &#8220;dbus_example_Service&#8221; vont entrain\u00e9 des comportements inconnus.<\/p>\n<pre class=\"code\">qdbuscpp2xml -S -M mainwindow.h -o org.homelinux.renaudguezennec.xml\r\n\r\nqdbusxml2cpp -c GuiAdaptor -a guiadaptor.h:guiadaptor.cpp org.homelinux.renaudguezennec.xml\r\n\r\nqdbusxml2cpp -c GuiAdaptor -p test.h:test.cpp org.homelinux.renaudguezennec.xml\r\n<\/pre>\n<p>La premi\u00e8re commande vous permet de g\u00e9n\u00e9rer un fichier xml: org.homelinux.renaudguezennec.xml qui contiendra l&#8217;ensemble de l&#8217;API de votre fichier .h.<br \/>\nLe resultat est de la forme suivante:<\/p>\n<\/div>\n<p>[pastacode lang=&#8221;markup&#8221; message=&#8221;Xml g\u00e9n\u00e9r\u00e9&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221; manual=&#8221;%3C!DOCTYPE%20node%20PUBLIC%20%22-%2F%2Ffreedesktop%2F%2FDTD%20D-BUS%20Object%20Introspection%201.0%2F%2FEN%22%20%22http%3A%2F%2Fwww.freedesktop.org%2Fstandards%2Fdbus%2F1.0%2Fintrospect.dtd%22%3E%0A%3Cnode%3E%0A%20%20%3Cinterface%20name%3D%22org.homelinux.renaudguezennec%22%3E%0A%20%20%20%20%3Csignal%20name%3D%22brightnessChanged%22%3E%0A%20%20%20%20%20%20%3Carg%20type%3D%22i%22%20direction%3D%22out%22%2F%3E%0A%20%20%20%20%3C%2Fsignal%3E%0A%20%20%20%20%3Cmethod%20name%3D%22setVolumeLevel%22%3E%0A%20%20%20%20%20%20%3Carg%20type%3D%22i%22%20direction%3D%22in%22%2F%3E%0A%20%20%20%20%3C%2Fmethod%3E%0A%20%20%3C%2Finterface%3E%0A%3C%2Fnode%3E&#8221;\/]<\/p>\n<div class=\"article\" lang=\"fr\">\n<pre class=\"code\"><\/pre>\n<p>La deuxi\u00e8me commande cr\u00e9e une classe GuiAdaptor (dans les fichiers: guiadaptor.h et guiadaptor.cpp) qui expose l&#8217;API d&#8217;\u00e9crire dans le xml. Cette classe sera utile cot\u00e9 service.<\/p>\n<p>La troisi\u00e8me commande cr\u00e9e une classe GuiAdaptor (dans les fichiers: test.h et test.cpp) que sera capable de contacter l&#8217;API d\u00e9crite dans le xml. Nous allons utiliser cette classe dans le client pour l&#8217;API d\u00e9crite dans le xml.<\/p>\n<p>L&#8217;\u00e9tape suivante consiste \u00e0 g\u00e9n\u00e9rer une classe Adaptor qui transformera vos signaux\/Slots Qt en message dbus. Il est utilis\u00e9 c\u00f4t\u00e9 service. Dans le main de votre programme, il convient d&#8217;instancier un adaptor g\u00e9n\u00e9r\u00e9 (ici: ControlPanelAdaptor), comme cela:<\/p>\n<p>[pastacode lang=&#8221;cpp&#8221; message=&#8221;Creation de service&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221; manual=&#8221;%23include%20%3CQtGui%2FQApplication%3E%0A%23include%20%22mainwindow.h%22%0A%23include%20%22guiadaptor.h%22%0Aint%20main(int%20argc%2C%20char%20*argv%5B%5D)%0A%7B%0A%20%20%20%20QApplication%20a(argc%2C%20argv)%3B%0A%20%20%20%20MainWindow%20w%3B%0A%20%20%20%20new%20GuiAdaptor(%26w)%3B%0A%20%20%20%20w.show()%3B%0A%0A%20%20%20%20QDBusConnection%20connection%20%3D%20QDBusConnection%3A%3AsessionBus()%3B%0A%20%20%20%20bool%20rel%20%3D%20connection.registerService(%22org.homelinux.renaudguezennec%22)%3B%0A%20%20%20%20rel%20%3D%20connection.registerObject(%22%2F%22%2C%26w)%3B%0A%0A%20%20%20%20return%20a.exec()%3B%0A%7D&#8221;\/]<\/p>\n<pre class=\"code\"><\/pre>\n<p>A ce stade, votre application peut-\u00eatre un service dbus. Il fournit une API \u00e0 travers DBus. Nous allons voir maintenant comment cr\u00e9er des clients qui vont utiliser cette API.<\/p>\n<p>Nous allons donc construire un nouveau projet : dbus_example_client. Il contiendra la r\u00e9ciproque du service. Le service est capable d&#8217;envoyer le signal brightnessChanged et re\u00e7oit son volume par l&#8217;appel \u00e0 setVolumeLevel. Le client lui sera capable d&#8217;appeler setVolumeLevel du service et de recevoir la valeur de brightnessChanged. Pour se faire, nous allons utilis\u00e9 la class GuiAdaptor (test.h et test.cpp) dans notre application cliente.<\/p>\n<p>[pastacode lang=&#8221;cpp&#8221; message=&#8221;Client Qt&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221; manual=&#8221;%23include%20%3CQtGui%2FQApplication%3E%0A%23include%20%22mainwindow.h%22%0A%23include%20%22test.h%22%0A%0Aint%20main(int%20argc%2C%20char%20*argv%5B%5D)%0A%7B%0A%20%20%20QApplication%20a(argc%2C%20argv)%3B%0A%20%20%20MainWindow%20w%3B%0A%0A%20%20%20%20GuiAdaptor*%20adapteur%20%3D%20new%20GuiAdaptor(%22org.homelinux.renaudguezennec%22%2C%20%0A%20%20%20%20%22%2F%22%2CQDBusConnection%3A%3AsessionBus()%2C0)%3B%0A%0A%20%20%20%20QObject%3A%3Aconnect(%26w%2CSIGNAL(volumeChanged(int))%2Cadapteur%2C%0A%20%20%20%20SLOT(setVolumeLevel(int)))%3B%0A%0A%20%20%20%20QObject%3A%3Aconnect(adapteur%2CSIGNAL(brightnessChanged(int))%2C%26w%2C%0A%20%20%20%20SLOT(setBrightnessChanged(int)))%3B%0A%20%20%20%20w.show()%3B%0A%0A%20%20%20%20return%20a.exec()%3B%0A%7D&#8221;\/]<\/p>\n<pre class=\"code\"><\/pre>\n<p>Comme vous pouvez le voir, il suffit d&#8217;instancier une classe GuiAdaptor (#include &#8220;test.h&#8221;) et de connecter les signals et les slots de notre application avec cette instance. En l&#8217;occurence, notre application emet le signal volumeChanged(int), nous le lions au slot setVolumeLevel(int) de notre adapteur. Le signal \u00e9mit par l&#8217;adapteur est r\u00e9cup\u00e9r\u00e9 dans un slot de notre application.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Dbus Dbus est un bus syst\u00e8me de messagerie. C&#8217;est un moyen simple pour des applications de communiquer entre elles. En plus de la communication interprocessus, Dbus est aussi un outil aidant au cycle de vie du processus. Il peut vous permettre de n&#8217;autoriser qu&#8217;une seule instance de votre application ou de votre daemon. Il peut [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[80,23],"tags":[24,22,10,11],"class_list":["post-26","post","type-post","status-publish","format-standard","hentry","category-fr","category-tutorial","tag-dbus","tag-linux","tag-qt","tag-qt4"],"_links":{"self":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/26","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/comments?post=26"}],"version-history":[{"count":5,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/26\/revisions"}],"predecessor-version":[{"id":5079,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/26\/revisions\/5079"}],"wp:attachment":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/media?parent=26"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/categories?post=26"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/tags?post=26"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}