wayland學習(1)-協議解析工具實現
wayland核心協議為wayland/protocol/wayland.xml,其中部分程式碼如下所示:
<interface name="wl_display" version="1"> <description summary="core global object"> The core global object. This is a special singleton object. It is used for internal Wayland protocol features. </description> <request name="sync"> <description summary="asynchronous roundtrip"> The sync request asks the server to emit the 'done' event on the returned wl_callback object. Since requests are handled in-order and events are delivered in-order, this can be used as a barrier to ensure all previous requests and the resulting events have been handled. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the event serial. </description> <arg name="callback" type="new_id" interface="wl_callback" summary="callback object for the sync request"/> </request> <request name="get_registry"> <description summary="get global registry object"> This request creates a registry object that allows the client to list and bind the global objects available from the compositor. It should be noted that the server side resources consumed in response to a get_registry request can only be released when the client disconnects, not when the client side proxy is destroyed. Therefore, clients should invoke get_registry as infrequently as possible to avoid wasting memory. </description> <arg name="registry" type="new_id" interface="wl_registry" summary="global registry object"/> </request> <event name="error"> <description summary="fatal error event"> The error event is sent out when a fatal (non-recoverable) error has occurred. The object_id argument is the object where the error occurred, most often in response to a request to that object. The code identifies the error and is defined by the object interface. As such, each interface defines its own set of error codes. The message is a brief description of the error, for (debugging) convenience. </description> <arg name="object_id" type="object" summary="object where the error occurred"/> <arg name="code" type="uint" summary="error code"/> <arg name="message" type="string" summary="error description"/> </event> <enum name="error"> <description summary="global error values"> These errors are global and can be emitted in response to any server request. </description> <entry name="invalid_object" value="0" summary="server couldn't find object"/> <entry name="invalid_method" value="1" summary="method doesn't exist on the specified interface"/> <entry name="no_memory" value="2" summary="server is out of memory"/> </enum> <event name="delete_id"> <description summary="acknowledge object ID deletion"> This event is used internally by the object ID management logic. When a client deletes an object, the server will send this event to acknowledge that it has seen the delete request. When the client receives this event, it will know that it can safely reuse the object ID. </description> <arg name="id" type="uint" summary="deleted object ID"/> </event> </interface>
通過wayland自帶工具wayland-scanner可以生成wayland-client-protocol.h,wayland-protocol.c,wayland-server-protocol.h三個檔案,該工具的具體實現為wayland/src/scanner.c,下面對其實現進行具體分析。
程式碼中定義了以下幾個主要型別:
包括協議,介面,訊息,引數型別,解析上下文,著重看下介面的定義,其中包含三個wl_list,分別為xml檔案中定義的request,event,enum。request為wayland中client端向server端傳送的請求,event為wayland中server端向client端傳送的事件,event和request都被定義為一種message,enum為協議中定義的enum值。struct protocol { char *name; char *uppercase_name; struct wl_list interface_list; int type_index; int null_run_length; char *copyright; struct description *description; bool core_headers; }; struct interface { struct location loc; char *name; char *uppercase_name; int version; int since; struct wl_list request_list; struct wl_list event_list; struct wl_list enumeration_list; struct wl_list link; struct description *description; }; struct message { struct location loc; char *name; char *uppercase_name; struct wl_list arg_list; struct wl_list link; int arg_count; int new_id_count; int type_index; int all_null; int destructor; int since; struct description *description; }; enum arg_type { NEW_ID, INT, UNSIGNED, FIXED, STRING, OBJECT, ARRAY, FD }; struct parse_context { struct location loc; XML_Parser parser; struct protocol *protocol; struct interface *interface; struct message *message; struct enumeration *enumeration; struct description *description; char character_data[8192]; unsigned int character_data_length; };
生成兩個標頭檔案的函式為emit_header,其中
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION); printf("#ifndef %s_%s_PROTOCOL_H\n" "#define %s_%s_PROTOCOL_H\n" "\n" "#include <stdint.h>\n" "#include <stddef.h>\n" "#include \"%s\"\n\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n\n", protocol->uppercase_name, s, protocol->uppercase_name, s, get_include_name(protocol->core_headers, side)); if (side == SERVER) printf("struct wl_client;\n" "struct wl_resource;\n\n"); emit_mainpage_blurb(protocol, side);
生成標頭檔案字首相關程式碼,以wayland-server-protocol.h為例,生成程式碼如下:
/* Generated by wayland-scanner 1.14.90 */
#ifndef WAYLAND_SERVER_PROTOCOL_H
#define WAYLAND_SERVER_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-server.h"
#ifdef __cplusplus
extern "C" {
#endif
struct wl_client;
struct wl_resource;
/**
* @page page_wayland The wayland protocol
* @section page_ifaces_wayland Interfaces
* - @subpage page_iface_wl_display - core global object
* - @subpage page_iface_wl_registry - global registry object
* - @subpage page_iface_wl_callback - callback object
* - @subpage page_iface_wl_compositor - the compositor singleton
* - @subpage page_iface_wl_shm_pool - a shared memory pool
* - @subpage page_iface_wl_shm - shared memory support
* - @subpage page_iface_wl_buffer - content for a wl_surface
* - @subpage page_iface_wl_data_offer - offer to transfer data
* - @subpage page_iface_wl_data_source - offer to transfer data
* - @subpage page_iface_wl_data_device - data transfer device
* - @subpage page_iface_wl_data_device_manager - data transfer interface
* - @subpage page_iface_wl_shell - create desktop-style surfaces
* - @subpage page_iface_wl_shell_surface - desktop-style metadata interface
* - @subpage page_iface_wl_surface - an onscreen surface
* - @subpage page_iface_wl_seat - group of input devices
* - @subpage page_iface_wl_pointer - pointer input device
* - @subpage page_iface_wl_keyboard - keyboard input device
* - @subpage page_iface_wl_touch - touchscreen input device
* - @subpage page_iface_wl_output - compositor output region
* - @subpage page_iface_wl_region - region interface
* - @subpage page_iface_wl_subcompositor - sub-surface compositing
* - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface
* @section page_copyright_wayland Copyright
* <pre>
*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2010-2011 Intel Corporation
* Copyright © 2012-2013 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* </pre>
*/
隨後將xml檔案中定義的介面名稱儲存在動態陣列wl_array(該動態陣列的具體實現會在後文具體分析) types中,實現程式碼如下所示:
wl_array_init(&types);
wl_list_for_each(i, &protocol->interface_list, link) {
emit_types_forward_declarations(protocol, &i->request_list, &types);
emit_types_forward_declarations(protocol, &i->event_list, &types);
}
wl_list_for_each(i, &protocol->interface_list, link) {
p = fail_on_null(wl_array_add(&types, sizeof *p));
*p = i->name;
}
對該陣列按照名稱進行排列
qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
在標頭檔案中定義各介面的結構體
prev = NULL;
wl_array_for_each(p, &types) {
if (prev && strcmp(*p, prev) == 0)
continue;
printf("struct %s;\n", *p);
prev = *p;
}
wl_array_release(&types);
printf("\n");
生成以下程式碼
struct wl_buffer;
struct wl_callback;
struct wl_compositor;
struct wl_data_device;
struct wl_data_device_manager;
struct wl_data_offer;
struct wl_data_source;
struct wl_display;
struct wl_keyboard;
struct wl_output;
struct wl_pointer;
struct wl_region;
struct wl_registry;
struct wl_seat;
struct wl_shell;
struct wl_shell_surface;
struct wl_shm;
struct wl_shm_pool;
struct wl_subcompositor;
struct wl_subsurface;
struct wl_surface;
struct wl_touch;
對於client端和server端,生成程式碼區別在於
if (side == SERVER) {
emit_structs(&i->request_list, i, side);
emit_opcodes(&i->event_list, i);
emit_opcode_versions(&i->event_list, i);
emit_opcode_versions(&i->request_list, i);
emit_event_wrappers(&i->event_list, i);
} else {
emit_structs(&i->event_list, i, side);
emit_opcodes(&i->request_list, i);
emit_opcode_versions(&i->event_list, i);
emit_opcode_versions(&i->request_list, i);
emit_stubs(&i->request_list, i);
}
函式emit_structs實現如下:
static void
emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
{
struct message *m;
struct arg *a;
int n;
if (wl_list_empty(message_list))
return;
printf("/**\n");
printf(" * @ingroup iface_%s\n", interface->name);
printf(" * @struct %s_%s\n", interface->name,
(side == SERVER) ? "interface" : "listener");
printf(" */\n");
printf("struct %s_%s {\n", interface->name,
(side == SERVER) ? "interface" : "listener");
wl_list_for_each(m, message_list, link) {
struct description *mdesc = m->description;
printf("\t/**\n");
if (mdesc) {
if (mdesc->summary)
printf("\t * %s\n", mdesc->summary);
printf("\t *\n");
desc_dump(mdesc->text, "\t * ");
}
wl_list_for_each(a, &m->arg_list, link) {
if (side == SERVER && a->type == NEW_ID &&
a->interface_name == NULL)
printf("\t * @param interface name of the objects interface\n"
"\t * @param version version of the objects interface\n");
if (a->summary)
printf("\t * @param %s %s\n", a->name,
a->summary);
}
if (m->since > 1) {
printf("\t * @since %d\n", m->since);
}
printf("\t */\n");
printf("\tvoid (*%s)(", m->name);
n = strlen(m->name) + 17;
if (side == SERVER) {
printf("struct wl_client *client,\n"
"%sstruct wl_resource *resource",
indent(n));
} else {
printf("void *data,\n"),
printf("%sstruct %s *%s",
indent(n), interface->name, interface->name);
}
wl_list_for_each(a, &m->arg_list, link) {
printf(",\n%s", indent(n));
if (side == SERVER && a->type == OBJECT)
printf("struct wl_resource *");
else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
printf("const char *interface, uint32_t version, uint32_t ");
else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
printf("void *");
else if (side == CLIENT && a->type == NEW_ID)
printf("struct %s *", a->interface_name);
else
emit_type(a);
printf("%s", a->name);
}
printf(");\n");
}
printf("};\n\n");
if (side == CLIENT) {
printf("/**\n"
" * @ingroup iface_%s\n"
" */\n", interface->name);
printf("static inline int\n"
"%s_add_listener(struct %s *%s,\n"
"%sconst struct %s_listener *listener, void *data)\n"
"{\n"
"\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
"%s(void (**)(void)) listener, data);\n"
"}\n\n",
interface->name, interface->name, interface->name,
indent(14 + strlen(interface->name)),
interface->name,
interface->name,
indent(37));
}
}
可以看到在client端生成的結構體為interface_name_listener,在server端生成的結構體為interface_name_interface,實現程式碼如下所示:
printf("struct %s_%s {\n", interface->name,
(side == SERVER) ? "interface" : "listener");
生成結果client端為
struct wl_display_listener
server端為
struct wl_display_interface
其中client端listener中定義對event響應的處理函式,而server端interface定義對request請求的處理函式。定義函式名稱程式碼如下:
printf("\t */\n");
printf("\tvoid (*%s)(", m->name);
n = strlen(m->name) + 17;
if (side == SERVER) {
printf("struct wl_client *client,\n"
"%sstruct wl_resource *resource",
indent(n));
} else {
printf("void *data,\n"),
printf("%sstruct %s *%s",
indent(n), interface->name, interface->name);
}
若在server端,前兩個引數為struct wl_client *client,struct wl_resource *resurce,若在client端,前兩個引數為void* data,struct interface_name *interface_name。接下來的引數為xml檔案中自己對該介面定義得到,以request請求get_register為例,引數如下所示:
<arg name="registry" type="new_id" interface="wl_registry"
summary="global registry object"/>
該引數名稱為register,型別為new_id,通過以下程式碼進行生成:
wl_list_for_each(a, &m->arg_list, link) {
printf(",\n%s", indent(n));
if (side == SERVER && a->type == OBJECT)
printf("struct wl_resource *");
else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
printf("const char *interface, uint32_t version, uint32_t ");
else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
printf("void *");
else if (side == CLIENT && a->type == NEW_ID)
printf("struct %s *", a->interface_name);
else
emit_type(a);
printf("%s", a->name);
}
進入emit_type分支,程式碼實現如下:
static void
emit_type(struct arg *a)
{
switch (a->type) {
default:
case INT:
case FD:
printf("int32_t ");
break;
case NEW_ID:
case UNSIGNED:
printf("uint32_t ");
break;
case FIXED:
printf("wl_fixed_t ");
break;
case STRING:
printf("const char *");
break;
case OBJECT:
printf("struct %s *", a->interface_name);
break;
case ARRAY:
printf("struct wl_array *");
break;
}
}
生成引數型別uint32_t,最終生成的程式碼為
struct wl_display_interface {
/**
* asynchronous roundtrip
*
* The sync request asks the server to emit the 'done' event on
* the returned wl_callback object. Since requests are handled
* in-order and events are delivered in-order, this can be used as
* a barrier to ensure all previous requests and the resulting
* events have been handled.
*
* The object returned by this request will be destroyed by the
* compositor after the callback is fired and as such the client
* must not attempt to use it after that point.
*
* The callback_data passed in the callback is the event serial.
* @param callback callback object for the sync request
*/
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
/**
* get global registry object
*
* This request creates a registry object that allows the client
* to list and bind the global objects available from the
* compositor.
*
* It should be noted that the server side resources consumed in
* response to a get_registry request can only be released when the
* client disconnects, not when the client side proxy is destroyed.
* Therefore, clients should invoke get_registry as infrequently as
* possible to avoid wasting memory.
* @param registry global registry object
*/
void (*get_registry)(struct wl_client *client,
struct wl_resource *resource,
uint32_t registry);
};
對於client端還需要生成相關proxy的註冊listener操作,該操作其實是對wl_proxy_add_listener的封裝,程式碼如下:
/**
* @ingroup iface_wl_display
*/
static inline int
wl_display_add_listener(struct wl_display *wl_display,
const struct wl_display_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_display,
(void (**)(void)) listener, data);
}
接下來對相關的request和event的op code進行巨集定義,程式碼如下:
#define WL_DISPLAY_ERROR 0
#define WL_DISPLAY_DELETE_ID 1
#define WL_DISPLAY_SYNC 0
#define WL_DISPLAY_GET_REGISTRY 1
對於server端,除了在interface_name為wl_display時,其他介面需要wrapper event事件,以wl_registry為例,該介面中包含兩個event,程式碼如下:
<event name="global">
<event name="global_remove">
生成程式碼函式為
emit_event_wrappers(&i->event_list, i);
生成出來的函式其實為wl_resource_post_event的封裝,程式碼如下:
static inline void
wl_registry_send_global(struct wl_resource *resource_, uint32_t name, const char *interface, uint32_t version)
{
wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL, name, interface, version);
}
static inline void
wl_registry_send_global_remove(struct wl_resource *resource_, uint32_t name)
{
wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL_REMOVE, name);
}
而對於client端,需要生成該介面的stub程式碼:
emit_stubs(&i->request_list, i);
對於每個request得到的程式碼為:
static inline void
wl_display_set_user_data(struct wl_display *wl_display, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data);
}
/** @ingroup iface_wl_display */
static inline void *
wl_display_get_user_data(struct wl_display *wl_display)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_display);
}
static inline uint32_t
wl_display_get_version(struct wl_display *wl_display)
{
return wl_proxy_get_version((struct wl_proxy *) wl_display);
}
而對於request引數不同,向server端傳送request的函式也不相同,程式碼如下:
if (ret && ret->interface_name == NULL) {
/* an arg has type ="new_id" but interface is not
* provided, such as in wl_registry.bind */
printf("\tstruct wl_proxy *%s;\n\n"
"\t%s = wl_proxy_marshal_constructor_versioned("
"(struct wl_proxy *) %s,\n"
"\t\t\t %s_%s, interface, version",
ret->name, ret->name,
interface->name,
interface->uppercase_name,
m->uppercase_name);
} else if (ret) {
/* Normal factory case, an arg has type="new_id" and
* an interface is provided */
printf("\tstruct wl_proxy *%s;\n\n"
"\t%s = wl_proxy_marshal_constructor("
"(struct wl_proxy *) %s,\n"
"\t\t\t %s_%s, &%s_interface",
ret->name, ret->name,
interface->name,
interface->uppercase_name,
m->uppercase_name,
ret->interface_name);
} else {
/* No args have type="new_id" */
printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
"\t\t\t %s_%s",
interface->name,
interface->uppercase_name,
m->uppercase_name);
}
若引數型別中包含new_id,但未提供interface,使用wl_proxy_marshal_constructor_versioned,例如:
static inline void *
wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor_versioned((struct wl_proxy *) wl_registry,
WL_REGISTRY_BIND, interface, version, name, interface->name, version, NULL);
return (void *) id;
}
若引數型別中包含new_id,且提供了interface,使用wl_proxy_marshal_constructor,例如:
static inline struct wl_surface *
wl_compositor_create_surface(struct wl_compositor *wl_compositor)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL);
return (struct wl_surface *) id;
}
若引數型別中不包含new_id,使用wl_proxy_marshal,例如:
static inline void
wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y)
{
wl_proxy_marshal((struct wl_proxy *) wl_pointer,
WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y);
}
依次對xml檔案中各個介面進行生成,即可得client和server端的兩個標頭檔案,下面對wayland-protocol.c中程式碼生成進行分析,生成程式碼的函式為:
emit_code(&protocol);
該函式中前面與emit_header類似,生成相關字首程式碼,隨後該函式生成一個wl_interface型別陣列,程式碼如下:
printf("static const struct wl_interface *types[] = {\n");
emit_null_run(protocol);
wl_list_for_each(i, &protocol->interface_list, link) {
emit_types(protocol, &i->request_list);
emit_types(protocol, &i->event_list);
}
printf("};\n\n");
其中emit_types實現如下所示:
static void
emit_types(struct protocol *protocol, struct wl_list *message_list)
{
struct message *m;
struct arg *a;
wl_list_for_each(m, message_list, link) {
if (m->all_null) {
m->type_index = 0;
continue;
}
m->type_index =
protocol->null_run_length + protocol->type_index;
protocol->type_index += m->arg_count;
wl_list_for_each(a, &m->arg_list, link) {
switch (a->type) {
case NEW_ID:
case OBJECT:
if (a->interface_name)
printf("\t&%s_interface,\n",
a->interface_name);
else
printf("\tNULL,\n");
break;
default:
printf("\tNULL,\n");
break;
}
}
}
}
request或者event中的引數型別為NEW_ID或者OBJECT時,陣列在該處的元素為引數的interface_name,否則為NULL,生成結果如下所示:
static const struct wl_interface *types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_callback_interface,
&wl_registry_interface,
&wl_surface_interface,
&wl_region_interface,
&wl_buffer_interface,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_shm_pool_interface,
NULL,
NULL,
&wl_data_source_interface,
&wl_surface_interface,
&wl_surface_interface,
NULL,
&wl_data_source_interface,
NULL,
&wl_data_offer_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_data_offer_interface,
&wl_data_offer_interface,
&wl_data_source_interface,
&wl_data_device_interface,
&wl_seat_interface,
&wl_shell_surface_interface,
&wl_surface_interface,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_buffer_interface,
NULL,
NULL,
&wl_callback_interface,
&wl_region_interface,
&wl_region_interface,
&wl_output_interface,
&wl_output_interface,
&wl_pointer_interface,
&wl_keyboard_interface,
&wl_touch_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_subsurface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_surface_interface,
};
static const struct wl_message wl_display_requests[] = {
{ "sync", "n", types + 8 },
{ "get_registry", "n", types + 9 },
};
static const struct wl_message wl_display_events[] = {
{ "error", "ous", types + 0 },
{ "delete_id", "u", types + 0 },
};
WL_EXPORT const struct wl_interface wl_display_interface = {
"wl_display", 1,
2, wl_display_requests,
2, wl_display_events,
};
隨後將wl_interface中的request和event封裝為wl_message型別,wl_message型別定義在檔案wayland-util中,程式碼如下:
struct wl_message {
const char *name;
const char *signature;
const struct wl_interface **types;
};
可以看出該結構體定義了訊息的名稱,簽名和引數為物件時,該物件引數的介面,生成得到程式碼如下:
static const struct wl_message wl_display_requests[] = {
{ "sync", "n", types + 8 },
{ "get_registry", "n", types + 9 },
};
static const struct wl_message wl_display_events[] = {
{ "error", "ous", types + 0 },
{ "delete_id", "u", types + 0 },
};
最後生成該interface的定義:
WL_EXPORT const struct wl_interface wl_display_interface = {
"wl_display", 1,
2, wl_display_requests,
2, wl_display_events,
};
WL_EXPORT const struct wl_interface wl_display_interface = {
"wl_display", 1,
2, wl_display_requests,
2, wl_display_events,
};
其中wl_interface的定義在wayland_util.c中,定義如下:
struct wl_interface {
const char *name;
int version;
int method_count;
const struct wl_message *methods;
int event_count;
const struct wl_message *events;
};
wl_interface結構體中定義了該介面的名稱,版本號,request數目,requeset方法,event數目,event方法。
以上。