From 83fc061c9cbe776de54fd335893f524793e4e92b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 4 Aug 2010 22:44:55 -0400 Subject: [PATCH] Introduce 'shell' object for moving and resizing surfaces in the compositor --- Makefile | 9 ++- TODO | 8 +++ clients/window.c | 141 ++++++++++++++++++-------------------------- compositor.c | 177 +++++++++++++++++++++++++++++++++++++++++++++---------- compositor.h | 29 ++++++++- protocol.xml | 8 +++ wayland-client.c | 34 +++++++++++ wayland-client.h | 12 ++++ 8 files changed, 299 insertions(+), 119 deletions(-) diff --git a/Makefile b/Makefile index fe2ea0f..cf449be 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,13 @@ libs = libwayland-server.so libwayland.so all : $(libs) compositor subdirs-all scanner +headers = \ + wayland-util.h \ + wayland-server-protocol.h \ + wayland.h \ + wayland-client-protocol.h \ + wayland-client.h \ + libwayland-server.so : \ wayland-protocol.o \ wayland.o \ @@ -60,7 +67,7 @@ install : $(libs) compositor install -d $(libdir) $(libdir)/pkgconfig ${udev_rules_dir} install $(libs) $(libdir) install wayland-server.pc wayland.pc $(libdir)/pkgconfig - install wayland-util.h wayland-client.h $(includedir) + install $(headers) $(includedir) install 70-wayland.rules ${udev_rules_dir} clean : subdirs-clean diff --git a/TODO b/TODO index 2ddcabf..7c555cb 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,13 @@ Core wayland protocol + - enter notify needs coordinates for cases where pointer focus + changes without motion (surfaces coming or going) + + - generate marshal stubs as static inline functions. + + - don't store globals on client side, require global_handler like + everything else. + - glyph cache - dnd, figure out large object transfer: through wayland protocol or diff --git a/clients/window.c b/clients/window.c index a7ed81b..c01ca05 100644 --- a/clients/window.c +++ b/clients/window.c @@ -52,6 +52,7 @@ struct display { struct wl_display *display; struct wl_compositor *compositor; + struct wl_shell *shell; struct wl_output *output; struct rectangle screen_allocation; EGLDisplay dpy; @@ -71,12 +72,11 @@ struct window { struct display *display; struct wl_surface *surface; const char *title; - struct rectangle allocation, saved_allocation, surface_allocation; + struct rectangle allocation, saved_allocation, pending_allocation; + int resize_edges; int redraw_scheduled; int minimum_width, minimum_height; int margin; - int drag_x, drag_y; - int state; int fullscreen; int decoration; struct input *grab_device; @@ -195,16 +195,16 @@ window_attach_surface(struct window *window) visual = wl_display_get_premultiplied_argb_visual(window->display->display); wl_surface_attach(window->surface, name, - window->surface_allocation.width, - window->surface_allocation.height, + window->allocation.width, + window->allocation.height, stride, visual); wl_surface_map(window->surface, - window->surface_allocation.x - window->margin, - window->surface_allocation.y - window->margin, - window->surface_allocation.width, - window->surface_allocation.height); + window->allocation.x, + window->allocation.y, + window->allocation.width, + window->allocation.height); wl_compositor_commit(window->display->compositor, 0); } @@ -229,7 +229,6 @@ window_draw_decorations(struct window *window) window->cairo_surface = display_create_surface(window->display, &window->allocation); - window->surface_allocation = window->allocation; width = window->allocation.width; height = window->allocation.height; @@ -274,7 +273,6 @@ window_draw_fullscreen(struct window *window) { window->cairo_surface = display_create_surface(window->display, &window->allocation); - window->surface_allocation = window->allocation; } void @@ -315,61 +313,11 @@ window_handle_motion(void *data, struct wl_input_device *input_device, int32_t x, int32_t y, int32_t sx, int32_t sy) { struct input *input = data; - struct window *window = input->pointer_focus; input->x = x; input->y = y; input->sx = sx; input->sy = sy; - - switch (window->state) { - case WINDOW_MOVING: - if (window->fullscreen) - break; - if (window->grab_device != input) - break; - window->allocation.x = window->drag_x + x; - window->allocation.y = window->drag_y + y; - wl_surface_map(window->surface, - window->allocation.x - window->margin, - window->allocation.y - window->margin, - window->allocation.width, - window->allocation.height); - wl_compositor_commit(window->display->compositor, 1); - break; - - case WINDOW_RESIZING_TOP: - case WINDOW_RESIZING_BOTTOM: - case WINDOW_RESIZING_LEFT: - case WINDOW_RESIZING_RIGHT: - case WINDOW_RESIZING_TOP_LEFT: - case WINDOW_RESIZING_TOP_RIGHT: - case WINDOW_RESIZING_BOTTOM_LEFT: - case WINDOW_RESIZING_BOTTOM_RIGHT: - if (window->fullscreen) - break; - if (window->grab_device != input) - break; - if (window->state & WINDOW_RESIZING_LEFT) { - window->allocation.x = x - window->drag_x + window->saved_allocation.x; - window->allocation.width = window->drag_x - x + window->saved_allocation.width; - } - if (window->state & WINDOW_RESIZING_RIGHT) - window->allocation.width = x - window->drag_x + window->saved_allocation.width; - if (window->state & WINDOW_RESIZING_TOP) { - window->allocation.y = y - window->drag_y + window->saved_allocation.y; - window->allocation.height = window->drag_y - y + window->saved_allocation.height; - } - if (window->state & WINDOW_RESIZING_BOTTOM) - window->allocation.height = y - window->drag_y + window->saved_allocation.height; - - if (window->resize_handler) - (*window->resize_handler)(window, - window->user_data); - else if (window->redraw_handler) - window_schedule_redraw(window); - break; - } } static void window_handle_button(void *data, struct wl_input_device *input_device, @@ -400,10 +348,8 @@ static void window_handle_button(void *data, struct wl_input_device *input_devic if (button == BTN_LEFT && state == 1) { switch (hlocation | vlocation) { case WINDOW_MOVING: - window->drag_x = window->allocation.x - input->x; - window->drag_y = window->allocation.y - input->y; - window->state = WINDOW_MOVING; - window->grab_device = input; + wl_shell_move(window->display->shell, + window->surface, input_device, time); break; case WINDOW_RESIZING_TOP: case WINDOW_RESIZING_BOTTOM: @@ -413,19 +359,11 @@ static void window_handle_button(void *data, struct wl_input_device *input_devic case WINDOW_RESIZING_TOP_RIGHT: case WINDOW_RESIZING_BOTTOM_LEFT: case WINDOW_RESIZING_BOTTOM_RIGHT: - window->drag_x = input->x; - window->drag_y = input->y; - window->saved_allocation = window->allocation; - window->state = hlocation | vlocation; - window->grab_device = input; - break; - default: - window->state = WINDOW_STABLE; + wl_shell_resize(window->display->shell, + window->surface, input_device, time, + hlocation | vlocation); break; } - } else if (button == BTN_LEFT && - state == 0 && window->grab_device == input) { - window->state = WINDOW_STABLE; } } @@ -519,6 +457,34 @@ static const struct wl_input_device_listener input_device_listener = { window_handle_keyboard_focus, }; +static void +handle_configure(void *data, struct wl_shell *shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + struct window *window = wl_surface_get_user_data(surface); + + window->resize_edges = edges; + window->pending_allocation.x = x; + window->pending_allocation.y = y; + window->pending_allocation.width = width; + window->pending_allocation.height = height; + + if (!(edges & 15)) + return; + + if (window->resize_handler) + (*window->resize_handler)(window, + window->user_data); + else if (window->redraw_handler) + window_schedule_redraw(window); +} + +static const struct wl_shell_listener shell_listener = { + handle_configure, +}; + void window_get_child_rectangle(struct window *window, struct rectangle *rectangle) @@ -542,12 +508,14 @@ window_set_child_size(struct window *window, if (!window->fullscreen) { width = rectangle->width + 20 + window->margin * 2; height = rectangle->height + 60 + window->margin * 2; - if (window->state & WINDOW_RESIZING_LEFT) - window->allocation.x -= - width - window->allocation.width; - if (window->state & WINDOW_RESIZING_TOP) - window->allocation.y -= - height - window->allocation.height; + + if (window->resize_edges & WINDOW_RESIZING_LEFT) + window->allocation.x += + window->allocation.width - width; + if (window->resize_edges & WINDOW_RESIZING_TOP) + window->allocation.y += + window->allocation.height - height; + window->allocation.width = width; window->allocation.height = height; } @@ -582,8 +550,13 @@ idle_redraw(void *data) { struct window *window = data; + if (window->resize_edges) + window->allocation = window->pending_allocation; + window->redraw_handler(window, window->user_data); + window->redraw_scheduled = 0; + window->resize_edges = 0; return FALSE; } @@ -696,7 +669,6 @@ window_create(struct display *display, const char *title, window->allocation.height = height; window->saved_allocation = window->allocation; window->margin = 16; - window->state = WINDOW_STABLE; window->decoration = 1; wl_surface_set_user_data(window->surface, window); @@ -809,6 +781,9 @@ display_handle_global(struct wl_display *display, wl_output_add_listener(d->output, &output_listener, d); } else if (wl_object_implements(object, "input_device", 1)) { display_add_input(d, object); + } else if (wl_object_implements(object, "shell", 1)) { + d->shell = (struct wl_shell *) object; + wl_shell_add_listener(d->shell, &shell_listener, d); } } diff --git a/compositor.c b/compositor.c index 165c547..3af3566 100644 --- a/compositor.c +++ b/compositor.c @@ -53,7 +53,6 @@ static const GOptionEntry option_entries[] = { { NULL } }; - static void wlsc_matrix_init(struct wlsc_matrix *matrix) { @@ -347,6 +346,19 @@ wlsc_surface_lower(struct wlsc_surface *surface) wl_list_insert(compositor->surface_list.prev, &surface->link); } +static void +wlsc_surface_update_matrix(struct wlsc_surface *es) +{ + wlsc_matrix_init(&es->matrix); + wlsc_matrix_scale(&es->matrix, es->width, es->height, 1); + wlsc_matrix_translate(&es->matrix, es->x, es->y, 0); + + wlsc_matrix_init(&es->matrix_inv); + wlsc_matrix_translate(&es->matrix_inv, -es->x, -es->y, 0); + wlsc_matrix_scale(&es->matrix_inv, + 1.0 / es->width, 1.0 / es->height, 1); +} + void wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs) { @@ -424,7 +436,7 @@ surface_destroy(struct wl_client *client, static void surface_attach(struct wl_client *client, - struct wl_surface *surface, uint32_t name, + struct wl_surface *surface, uint32_t name, int32_t width, int32_t height, uint32_t stride, struct wl_visual *visual) { @@ -438,9 +450,6 @@ surface_attach(struct wl_client *client, EGL_NONE }; - es->width = width; - es->height = height; - if (visual == &ec->argb_visual) es->visual = &ec->argb_visual; else if (visual == &ec->premultiplied_argb_visual) @@ -467,7 +476,6 @@ surface_attach(struct wl_client *client, EGL_DRM_IMAGE_MESA, (EGLClientBuffer) name, attribs); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, es->image); - } static void @@ -477,14 +485,12 @@ surface_map(struct wl_client *client, { struct wlsc_surface *es = (struct wlsc_surface *) surface; - wlsc_matrix_init(&es->matrix); - wlsc_matrix_scale(&es->matrix, width, height, 1); - wlsc_matrix_translate(&es->matrix, x, y, 0); - - wlsc_matrix_init(&es->matrix_inv); - wlsc_matrix_translate(&es->matrix_inv, -x, -y, 0); - wlsc_matrix_scale(&es->matrix_inv, 1.0 / width, 1.0 / height, 1); + es->x = x; + es->y = y; + es->width = width; + es->height = height; + wlsc_surface_update_matrix(es); } static void @@ -503,6 +509,49 @@ const static struct wl_surface_interface surface_interface = { }; static void +shell_move(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + + if (wd->grab == WLSC_DEVICE_GRAB_MOTION && + wd->grab_time == time && + &wd->pointer_focus->base == surface) { + wd->grab = WLSC_DEVICE_GRAB_MOVE; + wd->grab_dx = wd->pointer_focus->x - wd->grab_x; + wd->grab_dy = wd->pointer_focus->y - wd->grab_y; + } +} + +static void +shell_resize(struct wl_client *client, struct wl_shell *shell, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time, uint32_t edges) +{ + struct wlsc_input_device *wd = (struct wlsc_input_device *) device; + + if (edges == 0 || edges > 15 || + (edges & 3) == 3 || (edges & 12) == 12) + return; + + if (wd->grab == WLSC_DEVICE_GRAB_MOTION && + wd->grab_time == time && + &wd->pointer_focus->base == surface) { + wd->grab = edges; + wd->grab_dx = wd->pointer_focus->x - wd->grab_x; + wd->grab_dy = wd->pointer_focus->y - wd->grab_y; + wd->grab_width = wd->pointer_focus->width; + wd->grab_height = wd->pointer_focus->height; + } +} + +const static struct wl_shell_interface shell_interface = { + shell_move, + shell_resize +}; + +static void compositor_create_surface(struct wl_client *client, struct wl_compositor *compositor, uint32_t id) { @@ -600,10 +649,10 @@ pick_surface(struct wlsc_input_device *device, int32_t *sx, int32_t *sy) struct wlsc_compositor *ec = device->ec; struct wlsc_surface *es; - if (device->grab > 0) { - wlsc_surface_transform(device->grab_surface, + if (device->grab != WLSC_DEVICE_GRAB_NONE) { + wlsc_surface_transform(device->pointer_focus, device->x, device->y, sx, sy); - return device->grab_surface; + return device->pointer_focus; } wl_list_for_each(es, &ec->surface_list, link) { @@ -623,7 +672,7 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y) struct wlsc_compositor *ec = device->ec; struct wlsc_output *output; const int hotspot_x = 16, hotspot_y = 16; - int32_t sx, sy; + int32_t sx, sy, width, height; /* FIXME: We need some multi head love here. */ output = container_of(ec->output_list.next, struct wlsc_output, link); @@ -638,13 +687,72 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y) device->x = x; device->y = y; - es = pick_surface(device, &sx, &sy); - wlsc_input_device_set_pointer_focus(device, es, time); + switch (device->grab) { + case WLSC_DEVICE_GRAB_NONE: + case WLSC_DEVICE_GRAB_MOTION: + es = pick_surface(device, &sx, &sy); - if (es) - wl_surface_post_event(&es->base, &device->base, - WL_INPUT_DEVICE_MOTION, time, x, y, sx, sy); + wlsc_input_device_set_pointer_focus(device, es, time); + + if (es) + wl_surface_post_event(&es->base, &device->base, + WL_INPUT_DEVICE_MOTION, + time, x, y, sx, sy); + break; + + case WLSC_DEVICE_GRAB_MOVE: + es = device->pointer_focus; + es->x = x + device->grab_dx; + es->y = y + device->grab_dy;; + wl_surface_post_event(&es->base, &ec->shell, + WL_SHELL_CONFIGURE, + time, device->grab, + &es->base, es->x, es->y, + es->width, es->height); + + wlsc_surface_update_matrix(es); + + break; + + case WLSC_DEVICE_GRAB_RESIZE_TOP: + case WLSC_DEVICE_GRAB_RESIZE_BOTTOM: + case WLSC_DEVICE_GRAB_RESIZE_LEFT: + case WLSC_DEVICE_GRAB_RESIZE_TOP_LEFT: + case WLSC_DEVICE_GRAB_RESIZE_BOTTOM_LEFT: + case WLSC_DEVICE_GRAB_RESIZE_RIGHT: + case WLSC_DEVICE_GRAB_RESIZE_TOP_RIGHT: + case WLSC_DEVICE_GRAB_RESIZE_BOTTOM_RIGHT: + case WLSC_DEVICE_GRAB_RESIZE_MASK: + es = device->pointer_focus; + + if (device->grab & WLSC_DEVICE_GRAB_RESIZE_LEFT) { + sx = x + device->grab_dx; + width = device->grab_x - x + device->grab_width; + } else if (device->grab & WLSC_DEVICE_GRAB_RESIZE_RIGHT) { + sx = device->grab_x + device->grab_dx; + width = x - device->grab_x + device->grab_width; + } else { + sx = device->grab_x + device->grab_dx; + width = device->grab_width; + } + + if (device->grab & WLSC_DEVICE_GRAB_RESIZE_TOP) { + sy = y + device->grab_dy; + height = device->grab_y - y + device->grab_height; + } else if (device->grab & WLSC_DEVICE_GRAB_RESIZE_BOTTOM) { + sy = device->grab_y + device->grab_dy; + height = y - device->grab_y + device->grab_height; + } else { + sy = device->grab_y + device->grab_dy; + height = device->grab_height; + } + + wl_surface_post_event(&es->base, &ec->shell, + WL_SHELL_CONFIGURE, time, device->grab, + &es->base, sx, sy, width, height); + break; + } wlsc_matrix_init(&device->sprite->matrix); wlsc_matrix_scale(&device->sprite->matrix, 64, 64, 1); @@ -663,19 +771,21 @@ notify_button(struct wlsc_input_device *device, surface = device->pointer_focus; if (surface) { - if (state) { + if (state && device->grab == WLSC_DEVICE_GRAB_NONE) { wlsc_surface_raise(surface); - device->grab++; - device->grab_surface = surface; + device->grab = WLSC_DEVICE_GRAB_MOTION; + device->grab_time = time; + device->grab_x = device->x; + device->grab_y = device->y; wlsc_input_device_set_keyboard_focus(device, surface, time); } else { - device->grab--; + device->grab = WLSC_DEVICE_GRAB_NONE; } - /* FIXME: Swallow click on raise? */ wl_surface_post_event(&surface->base, &device->base, - WL_INPUT_DEVICE_BUTTON, time, button, state); + WL_INPUT_DEVICE_BUTTON, + time, button, state); wlsc_compositor_schedule_repaint(compositor); } @@ -753,13 +863,10 @@ handle_surface_destroy(struct wlsc_listener *listener, int32_t sx, sy; uint32_t time = get_time(); - if (device->grab_surface == surface) { - device->grab_surface = NULL; - device->grab = 0; - } if (device->keyboard_focus == surface) wlsc_input_device_set_keyboard_focus(device, NULL, time); if (device->pointer_focus == surface) { + device->grab = WLSC_DEVICE_GRAB_NONE; focus = pick_surface(device, &sx, &sy); wlsc_input_device_set_pointer_focus(device, focus, time); fprintf(stderr, "lost pointer focus surface, reverting to %p\n", focus); @@ -956,6 +1063,12 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) wl_display_set_compositor(display, &ec->base, &compositor_interface); + ec->shell.interface = &wl_shell_interface; + ec->shell.implementation = (void (**)(void)) &shell_interface; + wl_display_add_object(display, &ec->shell); + if (wl_display_add_global(display, &ec->shell, NULL)) + return -1; + add_visuals(ec); wl_list_init(&ec->surface_list); diff --git a/compositor.h b/compositor.h index 0129c84..7b42eb7 100644 --- a/compositor.h +++ b/compositor.h @@ -56,6 +56,22 @@ struct wlsc_output { int32_t x, y, width, height; }; +/* These should be part of the protocol */ +enum wlsc_grab_type { + WLSC_DEVICE_GRAB_NONE = 0, + WLSC_DEVICE_GRAB_RESIZE_TOP = 1, + WLSC_DEVICE_GRAB_RESIZE_BOTTOM = 2, + WLSC_DEVICE_GRAB_RESIZE_LEFT = 4, + WLSC_DEVICE_GRAB_RESIZE_TOP_LEFT = 5, + WLSC_DEVICE_GRAB_RESIZE_BOTTOM_LEFT = 6, + WLSC_DEVICE_GRAB_RESIZE_RIGHT = 8, + WLSC_DEVICE_GRAB_RESIZE_TOP_RIGHT = 9, + WLSC_DEVICE_GRAB_RESIZE_BOTTOM_RIGHT = 10, + WLSC_DEVICE_GRAB_RESIZE_MASK = 15, + WLSC_DEVICE_GRAB_MOVE = 16, + WLSC_DEVICE_GRAB_MOTION = 17 +}; + struct wlsc_input_device { struct wl_object base; int32_t x, y; @@ -63,12 +79,16 @@ struct wlsc_input_device { struct wlsc_surface *sprite; struct wl_list link; - int grab; - struct wlsc_surface *grab_surface; struct wlsc_surface *pointer_focus; struct wlsc_surface *keyboard_focus; struct wl_array keys; + enum wlsc_grab_type grab; + uint32_t grab_time; + int32_t grab_x, grab_y; + int32_t grab_width, grab_height; + int32_t grab_dx, grab_dy; + struct wlsc_listener listener; }; @@ -82,6 +102,9 @@ struct wlsc_compositor { GLuint proj_uniform, tex_uniform; struct wl_display *wl_display; + /* We implement the shell interface. */ + struct wl_object shell; + /* There can be more than one, but not right now... */ struct wlsc_input_device *input_device; @@ -117,7 +140,7 @@ struct wlsc_surface { struct wl_visual *visual; GLuint texture; EGLImageKHR image; - int width, height; + int32_t x, y, width, height; struct wl_list link; struct wlsc_matrix matrix; struct wlsc_matrix matrix_inv; diff --git a/protocol.xml b/protocol.xml index b5cb783..a0c32a7 100644 --- a/protocol.xml +++ b/protocol.xml @@ -49,15 +49,23 @@ + + + + + + + + diff --git a/wayland-client.c b/wayland-client.c index eb9d698..561f900 100644 --- a/wayland-client.c +++ b/wayland-client.c @@ -85,6 +85,10 @@ struct wl_output { int32_t width, height; }; +struct wl_shell { + struct wl_proxy proxy; +}; + struct wl_input_device { struct wl_proxy proxy; }; @@ -229,6 +233,33 @@ wl_output_add_listener(struct wl_output *output, (void (**)(void)) listener, data); } +WL_EXPORT int +wl_shell_add_listener(struct wl_shell *shell, + const struct wl_shell_listener *listener, + void *data) +{ + return wl_proxy_add_listener(&shell->proxy, + (void (**)(void)) listener, data); +} + +WL_EXPORT void +wl_shell_move(struct wl_shell *shell, + struct wl_surface *surface, struct wl_input_device *device, + uint32_t time) +{ + wl_proxy_marshal(&shell->proxy, + WL_SHELL_MOVE, surface, device, time); +} + +WL_EXPORT void +wl_shell_resize(struct wl_shell *shell, + struct wl_surface *surface, struct wl_input_device *device, + uint32_t time, uint32_t edges) +{ + wl_proxy_marshal(&shell->proxy, + WL_SHELL_RESIZE, surface, device, time, edges); +} + static void add_visual(struct wl_display *display, struct wl_global *global) { @@ -325,6 +356,9 @@ display_handle_global(void *data, else if (strcmp(global->interface, "input_device") == 0) wl_proxy_create_for_global(display, global, &wl_input_device_interface); + else if (strcmp(global->interface, "shell") == 0) + wl_proxy_create_for_global(display, global, + &wl_shell_interface); } static void diff --git a/wayland-client.h b/wayland-client.h index 482e32d..4f94a8b 100644 --- a/wayland-client.h +++ b/wayland-client.h @@ -75,6 +75,18 @@ wl_compositor_add_listener(struct wl_compositor *compostior, const struct wl_compositor_listener *listener, void *data); +int +wl_shell_add_listener(struct wl_shell *shell, + const struct wl_shell_listener *listener, + void *data); +void +wl_shell_move(struct wl_shell *shell, + struct wl_surface *surface, struct wl_input_device *device, + uint32_t time); +void +wl_shell_resize(struct wl_shell *shell, + struct wl_surface *surface, struct wl_input_device *device, + uint32_t time, uint32_t edges); void wl_surface_destroy(struct wl_surface *surface); void wl_surface_attach(struct wl_surface *surface, uint32_t name, -- 2.7.4