客户端真正的对象结构体
struct wl_proxy { struct wl_object object; struct wl_display *display; struct wl_event_queue *queue; uint32_t flags; int refcount; void *user_data; wl_dispatcher_func_t dispatcher; uint32_t version; };
Wayland协议里面的那些interface的对象在客户端其实真正的结构体是wl_proxy,而那些结构体都是不存在的,只是一个声明而已,根本不存在。如果读者有看过wayland的源码,会发现一个问题,就是wayland协议里面的那些interface对象,从来都不是程序员自己创建出来的,而是通过wayland的一些接口返回回来的。全部都是,无一例外。读者如果不相信可以自己去找找,并且可以自己尝试创建那些对象,肯定是会报错的,因为那些结构体都是不存在的,创建会编译出错
这 所谓的interface对象是啥呢,看看wayland.xml的描述
<interface name="wl_buffer" version="1"> <description summary="content for a wl_surface"> A buffer provides the content for a wl_surface. Buffers are created through factory interfaces such as wl_drm, wl_shm or similar. It has a width and a height and can be attached to a wl_surface, but the mechanism by which a client provides and updates the contents is defined by the buffer factory interface. </description> <request name="destroy" type="destructor"> <description summary="destroy a buffer"> Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach. </description> </request> <event name="release"> <description summary="compositor releases buffer"> Sent when this wl_buffer is no longer used by the compositor. The client is now free to reuse or destroy this buffer and its backing storage. If a client receives a release event before the frame callback requested in the same wl_surface.commit that attaches this wl_buffer to a surface, then the client is immediately free to reuse the buffer and its backing storage, and does not need a second buffer for the next surface content update. Typically this is possible, when the compositor maintains a copy of the wl_surface contents, e.g. as a GL texture. This is an important optimization for GL(ES) compositors with wl_shm clients. </description> </event> </interface>
一个wl_buffer就是一个Interface对象.
【服务器端的interface对象是在server端创建并返回的】
服务器端真正的对象结构体
struct wl_resource { struct wl_object object; wl_resource_destroy_func_t destroy; struct wl_list link; struct wl_signal destroy_signal; struct wl_client *client; void *data; };
服务器端所有的interface对象全部都是wl_resource结构体对象.
现在,我们开始通过对结构体之间关系的剖析,逐步把各个零散的概念串联起来
可以看到wl_interface就是贯穿这些结构的核心,也正是wayland.xml中大费周章描述的interface对象。
一个wayland协议xml包含一个或者多个interface, 一个interface里面包含一个或者多个request和event
举个栗子:
<interface name="wl_surface" version="4"> <request name="attach"> <arg name="buffer" type="object" interface="wl_buffer" allow-null="true" summary="buffer of surface contents"/> <arg name="x" type="int" summary="surface-local x coordinate"/> <arg name="y" type="int" summary="surface-local y coordinate"/> </request> </interface>
这里wl_surface这个interface对象,有一个名叫attach的方法,这个方法的参数如下:
第一个参数名是buffer, 类型是一个wl_buffer的指针,并且可以为空,其注释为 buffer of surface contents
第二个参数是 int x, 描述是surface-local x coordinate
第三个参数是 int y, 描述是surface-local y coordinate
翻译下来,这个函数大概就是:
void wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y);
第一个参数可以理解为wl_surface的this指针,指出是哪个对象要调用和这个接口。
好了,这里都是xml层面的描述,到了C的层面,这些内容都由wl_message结构体来描述。
其中以signature为相对比较重要,这里还是举个栗子:
以wl_display 的 delete_id为例,它只有一个uint的参数,那么这个结构体就是
{“delete_id”, "u", [NULL]}
NULL意味着uint的参数是一个元对象(primitive), 没有对应的wl_interface
再看一个栗子,比如上面讲到的那个wl_surface的attach方法:
其对应的wl_message结构体就应该是{ “attach”, "4?oii", [&wl_buffer, NULL, NULL] }
后两个NULL的意思是对于后面两个int参数,没有对应的interface对象
好的,到这一步就可以比较深入的了解wayland解析协议文件的输出文件了:
一个协议源文件:里面保存了xml协议文件里面所有的interface转换而成的wl_interface结构体变量,包括wl_message结构体记录的request和event函数。
一个客户端使用的头文件:里面封装了wl_proxy转换成指定interface假声明的结构体操作的接口函数,以及request函数的实现,但是这个request只是把请求发送到服务器端,实际调用是在服务器端进行。最后,文件里面还封装了一个回调函数的结构体,成员就是所有的event函数指针,需要客户端去实现,并设置到interface的对象里面,该文件生成了这个设置的接口,实际就是填充到wl_object结构体的implementation变量中。
一个服务器端头文件,里面基本和客户端一样的组成。只是结构体是wl_resource,函数结构体的成员是所有request的函数指针。以及所有的event的实现。
也就是说,客户端需要程序员自己实现事件(event),服务器端需要程序员实现请求(request)。