这部分的内容:
- GObject介绍
- 使用XML文件定义D-Bus接口
- 自动生成proxy/stub代码
- 创建一个简单的D-Bus对象
- 通过D-Bus发布一个GType类型
- 客户端如何使用Glib封装过的D-Bus
- D-Bus的自省功能
GObject介绍
为了在运行时把GTK+ widgets绑定到解释语言,一些牛人就用C语言实现了相对难以理解的面向对象的机制。根据你个人的爱好,你可以把这种面向对象称之为GObject或者GType。GType是GObject的底层基础。GObject/GType是Glib的一部分,并且单独编译成一个库:libgobject,对于GObject的详细介绍,大家可以到网上google一下,另外还要仔细阅读其代码,非常巧妙的实现!
这里的例子:实现一个非继承的类,类的接口去访问和修改两个私有的成员变量:value1和vaule2, value1是32位的整数,value2是一个gdouble类型的数据。
我们需要实现类构造函数和对象构造函数。这里,这两个构造函数都比较简短。如果你了解C++,你会发现这里怎么有两个构造函数呢?C++只有一个啊!不错,这就是GObject别扭的地方。慢慢你就会习惯的,当你很喜欢它后,你可能觉得C++是个另类。因为你了解C++的构造函数比较早,这个晚了些时候。
使用XML文件定义D-Bus接口:
由于我们主要的目的是做一个可以在D-Bus中使用的对象,因此我们从一个最简单的地方入手,通过dbus-binding-tool工具,这个工具会自动由XML文件生成client和server端的代码。我们就是把需要的接口安装XML语法定义在一个XML文件中就行了。
定义“方法”,即函数:用method来包含,其name是指定这个函数的名字,这个指定的名字会拷贝到生成的stub代码里面;函数method带一个参数:new_value, 用 包含。其中对于参数类型(type)的的形式,需要参考D-Bus的参数类型定义。
// direction表示入口参数还是出口参数,in:入口; out: 出口参数,如果不指定in或者out, 默认为in;
// type 的指定要参考D-Bus的类型定义,见下表;
其中,最难搞的就是要严格指定参数(arg)的类型(type),正是这个type来定义参数的数据类型,D-Bus定义的参数类型如下:
|
Conventional Name
|
Code
|
Description
|
INVALID |
0 (ASCII NUL)
|
Not a valid type code, used to terminate signatures
|
BYTE |
121 (ASCII 'y')
|
8-bit unsigned integer
|
BOOLEAN |
98 (ASCII 'b')
|
Boolean value, 0 is
FALSE and 1 is TRUE. Everything else is invalid. |
INT16 |
110 (ASCII 'n')
|
16-bit signed integer
|
UINT16 |
113 (ASCII 'q')
|
16-bit unsigned integer
|
INT32 |
105 (ASCII 'i')
|
32-bit signed integer
|
UINT32 |
117 (ASCII 'u')
|
32-bit unsigned integer
|
INT64 |
120 (ASCII 'x')
|
64-bit signed integer
|
UINT64 |
116 (ASCII 't')
|
64-bit unsigned integer
|
DOUBLE |
100 (ASCII 'd')
|
IEEE 754 double
|
STRING |
115 (ASCII 's')
|
UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes.
|
OBJECT_PATH |
111 (ASCII 'o')
|
Name of an object instance
|
SIGNATURE |
103 (ASCII 'g')
|
A type signature
|
ARRAY |
97 (ASCII 'a')
|
Array
|
STRUCT |
114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')')
|
Struct
|
VARIANT |
118 (ASCII 'v')
|
Variant type (the type of the value is part of the value itself)
|
DICT_ENTRY |
101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}')
|
Entry in a dict or map (array of key-value pairs)
|
我用蓝色标出的是比较常用的,你要根据你参数的需要,把上述第二列的类型码写到XML文件中去。开始你可能不习惯,慢慢就好了。
另外,D-Bus本身并不限制返回参数的个数,但是C语言只支持一个返回参数,因此如果你需要把其它需要携带回来的参数当作出口参数处理。其它的一些高级语言并不像C语言这样有限制。
下面是D-Bus函数所能支持的参数类型:(括号中是Glib对应的类型):
- b: boolean (gboolean)
- y: 8-bit unsigned integer (guint8)
- q/n: 16-bit unsigned/signed integer (guint16/gint16)
- u/i: 32-bit unsigned/signed integer (guint32/gint32)
- t/x: 64-bit unsigned/signed integer (guint64/gint64)
- d: IEEE 754 double precision floating point number (gdouble)
- s: UTF-8 encoded text string with NUL termination (only one NUL allowed) (gchar* with additional restrictions)
- a: Array of the following type specification (case-dependent)
- o/g/r/(/)/v/e/{/}: Complex types, please see the official D-Bus documentation on type signatures.
从这个列表可以看出,我们上面定义的函数:setvalue1有一个32位整形参数(new_value).这里定义的参数名称:new_value将会影响到所生成的stub代码,对于生成文档和D-Bus自省是非常有用的。
下面我们再定义另外一个函数:getvalue1, 这个函数用于返回当前对象的整数成员的值,没有入口参数,只有出口参数: cur_value。具体定义见下:
我们已经知道,D-Bus的method是隶属于interface的,就说一个interface可以有N个method, 在XML中,我们把这些method元素包含在interface元素中,借以表达这种隶属关系。这个interface的名字属性是可选的,你可以指定,也可以不指定,我们强烈推荐你写上这个名字,一是防止各个模块的interface重名,另外一个重要的功用是为了introspection.
再进一步,method隶属于interface, 那么interface又属于谁呢?隶属于object, 一个object可以有N个interface. 我们把interface元素包含在node元素内。在XML中,node是最顶层的元素了。我们这个例子里面,只实现了一个interface(binding tool会自动增加introspection接口的,因此不必在XML文件中指定),到此,我们就写完了一个最基本的XML文件,如下:
version="1.0" encoding="UTF-8" ?>
再对上面的最基本的XML接口定义文件做些扩充:增加DTD扫描,其实这个可以不用。另外还有就是增加了2个函数定义:get_value2, set_value2。
如果你需要写XML文件,强烈建议你在一个模板基础上写,就是拿个没有基本语法错误的模板,然后增加修改你的接口,这样容易成功,不要白手起家,不要在这个XML文件上面做过多的纠缠。
version="1.0" encoding="UTF-8" ?>
"-//freedesktop//DTD D-Bus Object Introspection 1.0//EN"
"">
写完XML文件后,下面我们是不是可以使用D-Bus工具来生成代码了?别急!我们还要对XML文件做些自动检查。主要检查两个方面:是否符合XML1.0规范;验证XML结构(即:元素是否成对匹配)。结构验证的规则是由DTD(Document Type Definition)文档规定的。D-Bus规定的XML格式如下:
|
|