基于weston的simple-shm案例
1.连接server:
wl_display_connect 接口通过socket建立与Server端的连接返回wl_display,display->registry = wl_display_get_registry(display->display) // 申请创建registry,得到代理对象wl_registry。这个个对象相当于Client在Server端放的一个用于嗅探资源的Observer。Client通过它得到Server端有哪些Global对象的信息。Server端有一系列的Global对象,如wl_compositor, wl_shm等
wl_registry_add_listener(display->registry,
®istry_listener, display);// 让Client监听刚才创建的wl_registry代理对象。这样, 当Client调用wl_display_get_registry()函数或者有新的Global对象加入到Server端时,Client就会收到event通知。
wl_display_roundtrip() // 等待前面的请求全被Server端处理完,它同步了Client和Server端。这意味着到这个函数返回时,Server端有几个Global对象,回调处理函数registry_handle_global()应该就已经被调用过几次了。 registry_handle_global()中会判断是当前这次event代表何种Global对象,然后调用wl_registry_bind()进行绑定,得到远程服务对象的本地代理对象。这些代理对象类型可以是wl_shm, wl_compositor等,但本质上都是wl_proxy类型:
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
{
struct display *d = data;
if (strcmp(interface, "wl_compositor") == 0) {
d->compositor =
wl_registry_bind(registry,
id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) {
d->wm_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
} else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
d->fshell = wl_registry_bind(registry,
id, &zwp_fullscreen_shell_v1_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
}
}
static void
registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
static struct display *
create_display(void)
{
struct display *display;
display = malloc(sizeof *display);
if (display == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
display->display = wl_display_connect(NULL);
assert(display->display);
display->has_xrgb = false;
display->registry = wl_display_get_registry(display->display);
wl_registry_add_listener(display->registry,
®istry_listener, display);
wl_display_roundtrip(display->display);
if (display->shm == NULL) {
fprintf(stderr, "No wl_shm global\n");
exit(1);
}
wl_display_roundtrip(display->display);
if (!display->has_xrgb) {
fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
exit(1);
}
return display;
}
2. 创建窗口:
window->surface = wl_compositor_create_surface() // 通过刚才绑定的wl_compositor服务创建Server端的weston_surface,返回代理对象 wl_surface。
xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface); // 通过刚才绑定的xdg_shell服务创建Server端的shell_surface,返回代理对象 xdg_surface。有些例子中用的是wl_shell_surface,它和xdg_surface的作用是一样的。xdg_surface是作为wl_shell_surface将来的替代品,但还没进Wayland核心协议。
为什么一个窗口要创建两个surface呢?因为Wayland协议假设Server端对Surface的管理分两个层次。以Weston为例,Compositor只负责合成(代码主要在compositor.c),它相当于Android中的SurfaceFligner,它所看到的主要是weston_surface。而Weston在启动时会加载shell模块(如desktop-shell.so,代码主要在desktop-shell/shell.c),它相当于Android中的WindowManagerService,它所看到的主要是shell_surface。shell_surface在结构上是weston_surface的进一步封装,为了做窗口管理。这样,合成渲染和窗口管理的模块既可以方便地相互访问又保证了较低的耦合度
static struct window *
create_window(struct display *display, int width, int height)
{
struct window *window;
window = zalloc(sizeof *window);
if (!window)
return NULL;
window->callback = NULL;
window->display = display;
window->width = width;
window->height = height;
window->surface = wl_compositor_create_surface(display->compositor);
if (display->wm_base) {
window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface);
assert(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window);
window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface);
assert(window->xdg_toplevel);
xdg_toplevel_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-shm");
wl_surface_commit(<