入り口に戻る

原文はこちら。

原文は CC-BY-SA-4.0 で公開されており、本サイトのこのページも同じ。

# 中級の D-Bus

実世界に存在する扱いづらいインターフェイスに直面したときに上手く QtDBus を活用するための知識。

- 概要
- 戻り値の型が複雑である場合
  - リスト
  - 辞書型(Dict)
  - 戻り値の型の任意の集合
- インターフェイスが Introspect に対応してない場合
  - プロパティ
  - シグナル

## 概要

「インターフェイスへのアクセス」で説明した基礎的な技法は、比較的単純なシグネチャを持つ 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>>();

### 辞書型(Dict)

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();

## インターフェイスが Introspect に対応してない場合

QDBusInterface は、遠隔の D-Bus インターフェイスのプロキシとして振る舞う。QDBusInterface は、内部調査(introspection)の機能を利用して、D-Bus シグナル及び D-Bus プロパティへの高水準のアクセスを可能にする。しかしながら、QDBusInterface によって内部調査を行うには対象となるオブジェクトがインターフェイス `org.freedesktop.DBus.Introspectable` に対応していなければならないのであるが、これは義務ではない。

### プロパティ

プロパティ群(`QObject::property()` を使ってアクセスする)を検出するには、`Introspect` が必要である。`Introspect` は存在しないが、遠隔インターフェイスのソース・コードを見ることでプロパティ群の名前とシグネチャがわかる場合、次の２つのメソッドを用いて手動で 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()` と同様である。但し、ラムダ式を含む新しい構文に対応していない点だけ異なっている。

前の記事

D-Bus インターフェイスへアクセスする

次の記事

D-Bus のインターフェイスを作成する

入り口に戻る