Inhaltsverzeichnis

24.9.5.1 Projekt 1 – DBusObserver – Teil 1

Im vorgestellten Programm soll festgestellt werden, ob ein USB-Stick eingesteckt wurde, welchen Namen (Label) der USB-Stick hat und unter welchem Pfad der USB-Stick erreichbar ist.

Wenn Sie ein Projekt für einen D-Bus-Observer entwickeln wollen, der eine Methode oder ein Signal beobachten soll, dann müssen Sie im Vorfeld die Antworten auf die folgenden Fragen einholen:

Die Antworten auf die Fragen können gegeben werden, wenn Sie die beiden Programme d-feet und dbus-monitor einsetzen und deren Ausgaben beim Einstecken eines USB-Sticks sorgfältig in Bezug auf die o.a. Aufgabenstellung analysieren. Der Einsatz des Programms d-feet wird im Kapitel D-Bus-Introspection vorgestellt.

Sehr gute Dienste leistet auch das Konsolen-Programm dbus-send für die Introspection:

$ dbus-send --session --print-reply –dest=org.gtk.Private.UDisks2VolumeMonitor \
 /org/gtk/Private/RemoteVolumeMonitor \
 org.freedesktop.DBus.Introspectable.Introspect > volumemonitor.introspection.xml

Hier ein Ausschnitt aus der XML-Datei:

...
  <signal name="VolumeAdded">
    <arg type="s" name="dbus_name"/>
    <arg type="s" name="id"/>
    <arg type="(ssssssbbssa{ss}sa{sv})" name="volume"/>
  </signal>
...

Ergänzend folgt ein Ausschnitt der Ausgaben des Programms dbus-monitor, wenn ein USB-Stick eingesteckt wurde und u.a. das dann ausgelöste D-Bus-Signal „VolumeAdded“ des Objekts /org/gtk/Private/RemoteVolumeMonitor mit den Werten seiner Argumente angezeigt wird:

signal sender=:1.10 -> dest=(null destination) serial=53 path=/org/gtk/Private/RemoteVolumeMonitor;
   interface=org.gtk.Private.RemoteVolumeMonitor; member=VolumeAdded
   string "org.gtk.Private.UDisks2VolumeMonitor"
   string "0x2493c70"
   struct {
      string "0x2493c70"
      string "2_GB_P"
      string ". GThemedIcon drive-removable-media-usb drive-removable-media drive-removable drive"
      string ". GThemedIcon drive-removable-media-usb-symbolic ... drive-removable drive"
      string ""
      string ""
      boolean true
      boolean true
      string "0x24b4d90"
      string ""
      array [
         dict entry(
            string "class"
            string "device"
         )
         dict entry(
            string "unix-device"
            string "/dev/sdd1"
         )
         dict entry(
            string "label"
            string "2_GB_P"
         )
         dict entry(
            string "uuid"
            string "38ea6e0b-a161-401d-a673-11c06cf1229e"
         )
      ]
      string "gvfs.time_detected_usec.1519387042284411"
      array [
      ]
   }

Damit und auch nach einem Blick in die Ausgaben des Konsolen-Programms d-feet ergaben sich die folgenden konkreten Antworten für die zutreffende Anwendung:

24.9.5.1.1 Signatur des Signals 'VolumeAdded'

Interessant in Bezug auf die o.a. Aufgabenstellung ist folgender Abschnitt zum Signal mit dem Namen „VolumeAdded“ aus dem sehr umfangreichen Inhalt des XML-Dokuments:

<signal name="VolumeAdded">
  <arg type="s" name="dbus_name"/>
  <arg type="s" name="id"/>
  <arg type="(ssssssbbssa{ss}sa{sv})" name="volume"/>
</signal>

Folgendes kann festgehalten werden:

Um die Anzahl und Typen von Argumenten zu beschreiben, die von Methoden und Signalen benötigt werden, verwendet D-Bus eine String-Kodierung in Form von Signaturen.

Ein einfaches und ausdrucksstarkes Format! Interessant wird es nun für das Projekt DBusObserver1, wie man die Datentypen des 3. Arguments auch in Gambas auf einen komplexen Daten-Typ abbilden kann. Richtig – es gibt eine einfache Möglichkeit, indem Sie dafür den Daten-Typ Struct verwenden:

Public Struct StructVariant
  String1 As String
  String2 As String
  String3 As String
  String4 As String
  String5 As String
  String6 As String
  Boolean1 As Boolean
  Boolean2 As Boolean
  String7 As String
  String8 As String
  Collection1 As Collection
  String9 As String
  Collection2 As Collection
End Struct

Public structSignalArgument3 As New StructVariant

24.9.5.1.2 Projekt 1 – Teil 2

Der Quelltext für das Projekt ist überschaubar, wird deshalb vollständig angegeben und anschließend kommentiert:

[1] ' Gambas class file
[2]
[3] Public Struct StructVariant
[4]   String1 As String
[5]   String2 As String
[6]   String3 As String
[7]   String4 As String
[8]   String5 As String
[9]   String6 As String
[10]   Boolean1 As Boolean
[11]   Boolean2 As Boolean
[12]   String7 As String
[13]   String8 As String
[14]   Collection1 As Collection
[15]   String9 As String
[16]   Collection2 As Collection
[17] End Struct
[18]
[19] Public structSignalArgument3 As New StructVariant
[20] Public hDBusObserver As DBusObserver
[21]
[22] Private $cDBus As DBusConnection
[23] Private $iOSMessageType As Integer
[24] Private $sOSObjectPath As String
[25] Private $sOSMember As String
[26] Private $sOSInterface As String
[27] Private $sOSDestination As String
[28]
[29] Public Sub Form_Open()
[30]
[31]   FMain.Resizable = True
[32]
[33]   $cDBus = DBus.Session
[34]   $iOSMessageType = DBus.Signal
[35]   $sOSObjectPath = "/org/gtk/Private/RemoteVolumeMonitor"
[36]   $sOSMember = "VolumeAdded" ' Member -> DBus-SignalName
[37]   $sOSInterface = "org.gtk.Private.RemoteVolumeMonitor"
[38]   $sOSDestination = "*"
[39]
[40]   hDBusObserver = New DBusObserver($cDBus, $iOSMessageType, $sOSObjectPath, $sOSMember, $sOSInterface, $sOSDestination) As "hDBusObserver"
[41]
[42]   FMain.Caption = "DBus-Observer:  Signal" & " ==> " & $sOSMember
[43]
[44] End
[45]
[46] Public Sub hDBusObserver_Message()
[47]
[48]   Dim k As Integer = 1
[49]   Dim vElement As Variant
[50]   Dim aArguments As Variant[]
[51]   Dim sDestination As String
[52]   Dim aObserverMessageTypes As String[] = ["DBus.Method", "DBus.Reply", "DBus.Error", "DBus.Signal"]
[53]
[54]   aArguments = hDBusObserver.Message.Arguments
[55]
[56]   structSignalArgument3.String1 = aArguments[2][0]
[57]   structSignalArgument3.String2 = aArguments[2][1]
[58]   structSignalArgument3.String3 = aArguments[2][2]
[59]   structSignalArgument3.String4 = aArguments[2][3]
[60]   structSignalArgument3.String5 = aArguments[2][4]
[61]   structSignalArgument3.String6 = aArguments[2][5]
[62]   structSignalArgument3.Boolean1 = aArguments[2][6]
[63]   structSignalArgument3.Boolean2 = aArguments[2][7]
[64]   structSignalArgument3.String7 = aArguments[2][8]
[65]   structSignalArgument3.String8 = aArguments[2][9]
[66]   structSignalArgument3.Collection1 = aArguments[2][10]
[67]   structSignalArgument3.String9 = aArguments[2][11]
[68]   structSignalArgument3.Collection2 = aArguments[2][12]
[69]
[70]   If Not hDBusObserver.Message.Destination Then
[71]      sDestination = "All Applications"
[72]   Else
[73]      sDestination = hDBusObserver.Message.Destination
[74]   Endif
[75]
[76]   txaResults.Insert(gb.NewLine)
[77]   txaResults.Insert("Message-Destination = " & sDestination & gb.NewLine)
[78]   txaResults.Insert("Message-Interface = " & hDBusObserver.Message.Interface & gb.NewLine)
[79]   txaResults.Insert("Message-Member = " & hDBusObserver.Message.Member & gb.NewLine)
[80]   txaResults.Insert("Message-Object = " & hDBusObserver.Message.Object & gb.NewLine)
[81]   txaResults.Insert("Message-Sender (ID) = " & hDBusObserver.Message.Sender & gb.NewLine)
[82]   txaResults.Insert("Message-Number = " & hDBusObserver.Message.Serial & gb.NewLine)
[83]   txaResults.Insert("Message-Type = " & aObserverMessageTypes[hDBusObserver.Message.Type - 1])
[84]   txaResults.Insert(gb.NewLine & gb.NewLine)
[85]
[86]   txaResults.Insert("Arguments of the \"VolumeAdded\" Signal:" & gb.NewLine)
[87]   txaResults.Insert(String$(61, "-") & gb.NewLine)
[88]   txaResults.Insert("<signal name=\"VolumeAdded\"" & gb.NewLine)
[89]   txaResults.Insert("  <arg type=\"s\" name=\"dbus_name\"/>" & gb.NewLine)
[90]   txaResults.Insert("  <arg type=\"s\" name=\"id\"/>" & gb.NewLine)
[91]   txaResults.Insert("  <arg type=\"(ssssssbbssa{ss}sa{sv})\" name=\"volume\"/>" & gb.NewLine)
[92]   txaResults.Insert("</signal>" & gb.NewLine & gb.NewLine)
[93]
[94]   txaResults.Insert("Number of arguments for Variant-Array 'Arguments' = " & aArguments.Count &
gb.NewLine)
[95]   txaResults.Insert(gb.NewLine)
[96]   txaResults.Insert("String:" & gb.NewLine)
[97]   txaResults.Insert("Arguments[0] = " & aArguments[0] & gb.NewLine)
[98]   txaResults.Insert("String:" & gb.NewLine)
[99]   txaResults.Insert("Arguments[1] = " & aArguments[1] & gb.NewLine)
[100]
[101]   txaResults.Insert("Data-Type Struct:" & gb.NewLine)
[102] ' 6x String
[103]   txaResults.Insert("Arguments[2][0] = " & aArguments[2][0] & gb.NewLine)
[104]   txaResults.Insert("Arguments[2][1] = " & aArguments[2][1] & gb.NewLine)
[105]   txaResults.Insert("Arguments[2][2] = " & aArguments[2][2] & gb.NewLine)
[106]   txaResults.Insert("Arguments[2][3] = " & aArguments[2][3] & gb.NewLine)
[107]   txaResults.Insert("Arguments[2][4] = " & aArguments[2][4] & gb.NewLine)
[108]   txaResults.Insert("Arguments[2][5] = " & aArguments[2][5] & gb.NewLine)
[109] ' 2x Boolean
[110]   txaResults.Insert("Arguments[2][6] = " & aArguments[2][6] & gb.NewLine)
[111]   txaResults.Insert("Arguments[2][7] = " & aArguments[2][7] & gb.NewLine)
[112] ' 2x String
[113]   txaResults.Insert("Arguments[2][8] = " & aArguments[2][8] & gb.NewLine)
[114]   txaResults.Insert("Arguments[2][9] = " & aArguments[2][9] & gb.NewLine)
[115] ' Collection 1 -> KeyType = String and DataType = String
[116]   txaResults.Insert("Collection 1 = Arguments[2][10]" & gb.NewLine)
[117]   If structSignalArgument3.Collection1.Count > 0 Then
[118]      For Each vElement In structSignalArgument3.Collection1
[119]        txaResults.Insert("Element " & Str(k) & "  :   " & structSignalArgument3.Collection1.Key)
[120]        txaResults.Insert(" = " & vElement & gb.NewLine)
[121]        Inc k
[122]      Next
[123]     Else
[124]      txaResults.Insert("Attention: The collection 1 is empty!" & gb.NewLine)
[125]   Endif
[126] ' 1x String
[127]   txaResults.Insert("Arguments[2][11] = " & aArguments[2][11] & gb.NewLine)
[128]   k = 1
[129] ' Collection 2 -> KeyType = String and DataType = Variant
[130]   txaResults.Insert("Collection 2 = Arguments[2][12]" & gb.NewLine)
[131]   If structSignalArgument3.Collection2.Count > 0 Then
[132]      For Each vElement In structSignalArgument3.Collection2
[133]        txaResults.Insert("Element " & Str(k) & "  :   " & structSignalArgument3.Collection2.Key)
[134]        txaResults.Insert(" = " & vElement & gb.NewLine)
[135]        Inc k
[136]      Next
[137]   Else
[138]      txaResults.Insert("Attention: The collection 2 is empty!" & gb.NewLine)
[139]   Endif
[140]
[141] End
[142]
[143] Public Sub Form_Close()
[144]   hDBusObserver = Null
[145]   FMain.Close()
[146] End

Kommentar:

Das Ergebnis der Beobachtung des Signals „VolumeAdded“ des Objekts des Objekts org.gtk.Private.UDisks2VolumeMonitor kann sich sehen lassen:

Abbildung 24.9.5.1.1: Auswertung der Beobachtung des Signals 'VolumeAdded' (Message-Member)

Das vorgestellte Projekt können Sie an andere zu beobachtende Nachrichten anpassen. Das gelingt Ihnen aber nur dann ohne Probleme, wenn Sie die Introspection für den ausgewählten Nachrichtentyp mit den empfohlenen Programmen mit Sorgfalt erneut ausführen, um u.a. die Signatur der Nachrichten zu ermitteln.

24.9.5.1.3 Projekt 2 – ObserverDBus – Signal 'MountAdded'

In einem weiteren Projekt wird Ihnen ein Observer für das Signal 'MountAdded' zur Erprobung zur Verfügung gestellt. Dabei wird auf den Daten-Typ Struct verzichtet und nur mit den Gambas-Datentypen Integer, String, Array und Collection gearbeitet, wie ein Blick in die Definitionsliste zeigt:

Dim k As Integer = 1
Dim vElement As Variant
Dim cCollection As Collection
Dim aArray As String[]
Dim aArguments As Variant[]
Dim sDestination As String
Dim aObserverMessageTypes As String[] = ["DBus.Method", "DBus.Reply", "DBus.Error", "DBus.Signal"]

Die Signatur der Nachricht – gegenüber dem Projekt 1 – ist völlig anders:

<signal name="MountAdded">
  <arg type="s" name="dbus_name"/>
  <arg type="s" name="id"/>
  <arg type="(ssssssbsassa{sv})" name="mount"/>
</signal>

Das ist die Ausgabe, wenn das Signal 'MountAdded' abgefangen und ausgewertet wurde:

Abbildung 24.9.5.1.2: Auswertung der Beobachtung des Signals 'MountAdded'

Im Kapitel 24.9.8.0 werden Ihnen die beiden Klassen DBusVariant und DBusValues vorgestellt, mit denen Sie die passenden, dbus-gerechten Daten für eigene Nachrichten für selbst deklarierte Signaturen aus den Daten mit Gambas-Datentypen erzeugen können. Zwei Projekte, in denen Gambas-Programme (Server/Client) D-Bus-Objekte exportieren und Dienste anbieten oder nutzen, ergänzen die beschriebene Theorie.

Download