Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QtDBus slot not working with expected prototype



  • Hello all,

    To keep it simple, I am trying to communicate with bluez using the QtDBus library. Specifically, I'm trying to connect to the InterfacesAdded signal part of org.freedesktop.DBus.ObjectManager.

    The dbus signal has the following prototype:
    Object Path, Dict of {String, Dict of {String, Variant}}.
    From my understanding, the Qt-equivalent of this would be:
    QDBusObjectPath, QMap<QString, QVariantMap>

    So I have my slot:

    typedef QMap<QString, QVariantMap> InterfaceList;
    Q_DECLARE_METATYPE(InterfaceList)
    
    void interfaces_added(const QDBusObjectPath &, InterfaceList);
    

    And my my connection:

    QDBusConnection::systemBus().connect("org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", this, SLOT(interfaces_added(const QDBusObjectPath &, InterfaceList)));
    

    But the function doesn't get called on the signal.

    What's interesting though is when I have my slot like this (with a matching connection):

    void interfaces_added(const QDBusObjectPath &, QMap<QString, QVariant>);
    

    my function gets called and I'm able to handle the signal (albeit haven't figured out how to get anything meaningful out of the QMap).

    I'm not really sure what to make of this. I don't believe its an issue with dbus becuase when using dbus-monitor I see the data in the expected format. For what its worth, I am able to connect to the InterfacesRemoved signal without any issues.

    Is Qt unable to handle more complex types like nested maps?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Disclaimer: I haven't used that module yet.

    Doesn't the QVariant parameter contain a QVariantMap ?



  • I tried printing out the data I was receiving, and this is an example of what I was getting (using the "incorrect" prototype):

    QMap(("org.bluez.Device1", QVariant(void*, 0x65))("org.freedesktop.DBus.Introspectable", QVariant(void*, 0x0))("org.freedesktop.DBus.Properties", QVariant(void*, 0x0)))
    

    For the most part, what I get makes sense, except for the QVariant(void*, 0x65) in the first entry. It doesn't seem to contain a QVariantMap.


  • Lifetime Qt Champion

    Do you know what data you should be receiving ?



  • Yeah instead of the QVariant I am expecting a QVariantMap (but the connection doesn't work with a slot with that kind of prototype).

    Here is an example of the data that would be received

             array [
                dict entry(
                   string "Address"
                   variant                   string "FF:FF:FF:FF:FF:FF"
                )
                dict entry(
                   string "AddressType"
                   variant                   string "random"
                )
                dict entry(
                   string "Name"
                   variant                   string "device name"
                )
                dict entry(
                   string "Alias"
                   variant                   string "device alias"
                )
                dict entry(
                   string "Paired"
                   variant                   boolean false
                )
                dict entry(
                   string "Trusted"
                   variant                   boolean false
                )
                dict entry(
                   string "Blocked"
                   variant                   boolean false
                )
                dict entry(
                   string "LegacyPairing"
                   variant                   boolean false
                )
                dict entry(
                   string "RSSI"
                   variant                   int16 -69
                )
                dict entry(
                   string "Connected"
                   variant                   boolean false
                )
                dict entry(
                   string "UUIDs"
                   variant                   array [
                         string "0000fea0-0000-1000-8000-00805f9b34fb"
                      ]
                )
                dict entry(
                   string "Adapter"
                   variant                   object path "/org/bluez/hci0"
                )
                dict entry(
                   string "ServiceData"
                   variant                   array [
                         dict entry(
                            string "00000000-0000-0000-0000-000000000000"
                            variant                            array of bytes [
                                  ff ff ff ff ff ff ff ff ff ff ff ff ff
                               ]
                         )
                      ]
                )
                dict entry(
                   string "ServicesResolved"
                   variant                   boolean false
                )
             ]
    

    where array is essentially the Map.



  • This question is a bit old now, but I ran into the same problem without finding a solution elsewhere, so maybe this will be useful for others to know.

    I tried exactly the same code as you, and found the the same issue of the signal not connecting properly. What worked for me was to add the following somewhere in the code (e.g. the class constructor) to get executed before the connect() call.

    #include <QDBusMetaType>
    
    // Add to code (e.g. constructor) to be run before the connect() call
    qDBusRegisterMetaType<InterfaceList>();
    

    The connect() call then returned true, the signal fired, and I was able to extract the object properties straight from the InterfaceList object passed with the signal.