実世界に存在する扱いづらいインタフェイスに直面したときに上手く QtDBus を活用するための知識。
「インタフェイスへのアクセス」で説明した基礎的な技法は、比較的単純なシグネチャを持つ D-Bus メソッドを利用するのには適している。けれども、現実によくあるもっと複雑なインタフェイスに対処するには、この記事で説明する別の技法も必要である。
戻り値の型が単一のプリミティブ(primitive)でなくそれより複雑な型であるメソッドを扱う場合、QtDBus では追加の設定が必要になる。Qt の型システム(Qt type system)によって戻り値を元の型に戻せる(demarshal)ように、戻り値の型を同システムに対して宣言する必要がある。
QtDBus においては、D-Bus メソッドが返す値のリストは QList で受け取る(mapped to QList)。Qt の型システムに対して、型として QList の適切な特殊化(specialisation)を宣言する必要がある。例を挙げる。
Q_DECLARE_METATYPE(QList<QDBusObjectPath>)
マクロ Q_DECLARE_METATYPE
は、ソースコードの中のコード・ブロックやメソッドの外側で使用しなければならない。最も適した使用場所は、ファイルの先頭である。
QtDBus に対しても、次のような文を用いて型を宣言する必要がある。
qDBusRegisterMetaType<QList<QDBusObjectPath>>();
DBus の Dict 型は、QMap で受け取る(map to QMap)必要がある。
D-Bus メソッドの中には、複数の値の任意の組み合わせを返すものがある。QDBusReply クラスでは、メソッドによって返される値の中の最初のものしか処理できない。そのため、残りの戻り値も取得したい場合、再び QDBusMessage を持ち出して使用することになる。QDBusAbstractInterface::call()
とその同類は、実際には QDBusMessage
を返す。そのため、QDBusReply
を使うとき、実際には、全ての戻り値が入っている QDBusMessage
から QDBusReply
を作り出しているのである。
QDBusMessage の取得方法がわかったので、arguments()
を用いて戻り値にアクセスすることができる。arguments()
は QList<QVariant>
を返す。
例えば、メソッド org.kde.DBusTute.Favourites.Get( out INT32 number, out STRING colour, out STRING flavour )
を使用するコードは次のようなものになる。
QDBusInterface iface( "org.kde.DBusTute", "/org/kde/DBusTute/Favourites", "org.kde.DBusTute.Favourites", QDBus::sessionBus()); QDBusMessage reply = iface.call( "Get" ); QList<QVariant> values = reply.arguments(); int favouriteNumber = values.takeFirst().toInt(); QString favouriteColour = values.takeFirst().toString(); QString favouriteFlavour = values.takeFirst().toString();
QDBusInterface は、遠隔の D-Bus インタフェイスのプロキシとして振る舞う。QDBusInterface は、内部調査(introspection)の機能を利用して、D-Bus シグナル及び D-Bus プロパティへの高水準のアクセスを可能にする。しかしながら、QDBusInterface によって内部調査を行うには対象となるオブジェクトがインタフェイス org.freedesktop.DBus.Introspectable
に対応していなければならないのであるが、これは義務ではない。
プロパティ群(QObject::property()
を使ってアクセスする)を検出するには、Introspect
が必要である。Introspect
は存在しないが、遠隔インタフェイスのソース・コードを見ることでプロパティ群の名前とシグネチャがわかる場合、次の2つのメソッドを用いて手動で D-Bus のプロパティ・システムを使用することができる。
org.freedesktop.DBus.Properties.Get (in STRING interface_name, in STRING property_name, out VARIANT value); org.freedesktop.DBus.Properties.Set (in STRING interface_name, in STRING property_name, in VARIANT value);
Introspect に対応していない場合、QObject::connect()
は、実行時にエラー 'no such signal'
を生ずる。
QtDBus では、このようなシグナルであっても低水準の手続きを使って接続可能である。それには、QDBusConnection::connect()
を使用する。現在 QDBusInterface とその手軽なメソッドである call()
を使用している場合、使用している QDBusInterface の接続(QDBusConnection)を取得し、その接続で connect()
を呼び出す。
QDBusInterface iface("org.kde.DBusTute", "/org/kde/DBusTute/Favourites", "org.kde.DBusTute.Favourites", QDBus::sessionBus()); iface.connection().connect("org.kde.DBusTute", "/org/kde/DBusTute/Favourites", "org.kde.DBusTute.Favourites", "FavouritesChanged", this, SLOT(favouritesChanged()));
接続メソッドの機能(semantics)は、通常の QObject::connect()
と同様である。但し、ラムダ式を含む新しい構文に対応していない点だけ異なっている。