2 * Copyright © 2013 Intel Corporation
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
31 #include <sys/epoll.h>
32 #include <sys/socket.h>
36 #include <EGL/eglext.h>
37 #include <GLES2/gl2.h>
38 #include <GLES2/gl2ext.h>
42 #include <wayland-client.h>
43 #define WL_HIDE_DEPRECATED
44 #include <wayland-server.h>
48 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
51 struct display *display;
52 struct window *window;
53 struct widget *widget;
54 struct wl_display *child_display;
55 struct task child_task;
57 EGLDisplay egl_display;
58 struct program *texture_program;
60 struct wl_list surface_list;
61 struct wl_list frame_callback_list;
64 struct nested_region {
65 struct wl_resource *resource;
66 pixman_region32_t region;
69 struct nested_surface {
70 struct wl_resource *resource;
71 struct wl_resource *buffer_resource;
72 struct nested *nested;
76 cairo_surface_t *cairo_surface;
79 struct nested_frame_callback {
80 struct wl_resource *resource;
84 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
85 static PFNEGLCREATEIMAGEKHRPROC create_image;
86 static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
87 static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
88 static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
89 static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
92 frame_callback(void *data, struct wl_callback *callback, uint32_t time)
94 struct nested *nested = data;
95 struct nested_frame_callback *nc, *next;
98 wl_callback_destroy(callback);
100 wl_list_for_each_safe(nc, next, &nested->frame_callback_list, link) {
101 wl_callback_send_done(nc->resource, time);
102 wl_resource_destroy(nc->resource);
104 wl_list_init(&nested->frame_callback_list);
106 /* FIXME: toytoolkit need a pre-block handler where we can
108 wl_display_flush_clients(nested->child_display);
111 static const struct wl_callback_listener frame_listener = {
116 redraw_handler(struct widget *widget, void *data)
118 struct nested *nested = data;
119 cairo_surface_t *surface;
121 struct rectangle allocation;
122 struct wl_callback *callback;
123 struct nested_surface *s;
125 widget_get_allocation(nested->widget, &allocation);
127 surface = window_get_surface(nested->window);
129 cr = cairo_create(surface);
130 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
136 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
139 wl_list_for_each(s, &nested->surface_list, link) {
140 display_acquire_window_surface(nested->display,
141 nested->window, NULL);
143 glBindTexture(GL_TEXTURE_2D, s->texture);
144 image_target_texture_2d(GL_TEXTURE_2D, s->image);
146 display_release_window_surface(nested->display,
149 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
150 cairo_set_source_surface(cr, s->cairo_surface,
153 cairo_rectangle(cr, allocation.x + 10,
155 allocation.width - 10,
156 allocation.height - 10);
163 cairo_surface_destroy(surface);
165 callback = wl_surface_frame(window_get_wl_surface(nested->window));
166 wl_callback_add_listener(callback, &frame_listener, nested);
170 keyboard_focus_handler(struct window *window,
171 struct input *device, void *data)
173 struct nested *nested = data;
175 window_schedule_redraw(nested->window);
179 handle_child_data(struct task *task, uint32_t events)
181 struct nested *nested = container_of(task, struct nested, child_task);
182 struct wl_event_loop *loop;
184 loop = wl_display_get_event_loop(nested->child_display);
186 wl_event_loop_dispatch(loop, -1);
187 wl_display_flush_clients(nested->child_display);
190 struct nested_client {
191 struct wl_client *client;
195 static struct nested_client *
196 launch_client(struct nested *nested, const char *path)
200 struct nested_client *client;
202 client = malloc(sizeof *client);
206 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
207 fprintf(stderr, "launch_client: "
208 "socketpair failed while launching '%s': %m\n",
219 fprintf(stderr, "launch_client: "
220 "fork failed while launching '%s': %m\n", path);
228 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
229 * get a non-CLOEXEC fd to pass through exec. */
230 clientfd = dup(sv[1]);
231 if (clientfd == -1) {
232 fprintf(stderr, "compositor: dup failed: %m\n");
236 snprintf(s, sizeof s, "%d", clientfd);
237 setenv("WAYLAND_SOCKET", s, 1);
239 execl(path, path, NULL);
241 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
248 client->client = wl_client_create(nested->child_display, sv[0]);
249 if (!client->client) {
252 fprintf(stderr, "launch_client: "
253 "wl_client_create failed while launching '%s'.\n",
264 destroy_surface(struct wl_resource *resource)
266 struct nested_surface *surface = wl_resource_get_user_data(resource);
268 wl_list_remove(&surface->link);
274 surface_destroy(struct wl_client *client, struct wl_resource *resource)
276 wl_resource_destroy(resource);
280 surface_attach(struct wl_client *client,
281 struct wl_resource *resource,
282 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
284 struct nested_surface *surface = wl_resource_get_user_data(resource);
285 struct nested *nested = surface->nested;
286 EGLint format, width, height;
287 cairo_device_t *device;
289 if (surface->buffer_resource)
290 wl_buffer_send_release(surface->buffer_resource);
292 surface->buffer_resource = buffer_resource;
293 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
294 EGL_TEXTURE_FORMAT, &format)) {
295 fprintf(stderr, "attaching non-egl wl_buffer\n");
299 if (surface->image != EGL_NO_IMAGE_KHR)
300 destroy_image(nested->egl_display, surface->image);
301 if (surface->cairo_surface)
302 cairo_surface_destroy(surface->cairo_surface);
305 case EGL_TEXTURE_RGB:
306 case EGL_TEXTURE_RGBA:
309 fprintf(stderr, "unhandled format: %x\n", format);
313 surface->image = create_image(nested->egl_display, NULL,
314 EGL_WAYLAND_BUFFER_WL, buffer_resource,
316 if (surface->image == EGL_NO_IMAGE_KHR) {
317 fprintf(stderr, "failed to create img\n");
321 query_buffer(nested->egl_display,
322 (void *) buffer_resource, EGL_WIDTH, &width);
323 query_buffer(nested->egl_display,
324 (void *) buffer_resource, EGL_HEIGHT, &height);
326 device = display_get_cairo_device(nested->display);
327 surface->cairo_surface =
328 cairo_gl_surface_create_for_texture(device,
329 CAIRO_CONTENT_COLOR_ALPHA,
333 window_schedule_redraw(nested->window);
337 surface_damage(struct wl_client *client,
338 struct wl_resource *resource,
339 int32_t x, int32_t y, int32_t width, int32_t height)
344 destroy_frame_callback(struct wl_resource *resource)
346 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
348 wl_list_remove(&callback->link);
353 surface_frame(struct wl_client *client,
354 struct wl_resource *resource, uint32_t id)
356 struct nested_frame_callback *callback;
357 struct nested_surface *surface = wl_resource_get_user_data(resource);
358 struct nested *nested = surface->nested;
360 callback = malloc(sizeof *callback);
361 if (callback == NULL) {
362 wl_resource_post_no_memory(resource);
366 callback->resource = wl_resource_create(client,
367 &wl_callback_interface, 1, id);
368 wl_resource_set_implementation(callback->resource, NULL, callback,
369 destroy_frame_callback);
371 wl_list_insert(nested->frame_callback_list.prev, &callback->link);
375 surface_set_opaque_region(struct wl_client *client,
376 struct wl_resource *resource,
377 struct wl_resource *region_resource)
379 fprintf(stderr, "surface_set_opaque_region\n");
383 surface_set_input_region(struct wl_client *client,
384 struct wl_resource *resource,
385 struct wl_resource *region_resource)
387 fprintf(stderr, "surface_set_input_region\n");
391 surface_commit(struct wl_client *client, struct wl_resource *resource)
396 surface_set_buffer_transform(struct wl_client *client,
397 struct wl_resource *resource, int transform)
399 fprintf(stderr, "surface_set_buffer_transform\n");
402 static const struct wl_surface_interface surface_interface = {
407 surface_set_opaque_region,
408 surface_set_input_region,
410 surface_set_buffer_transform
414 compositor_create_surface(struct wl_client *client,
415 struct wl_resource *resource, uint32_t id)
417 struct nested *nested = wl_resource_get_user_data(resource);
418 struct nested_surface *surface;
420 surface = zalloc(sizeof *surface);
421 if (surface == NULL) {
422 wl_resource_post_no_memory(resource);
426 surface->nested = nested;
428 display_acquire_window_surface(nested->display,
429 nested->window, NULL);
431 glGenTextures(1, &surface->texture);
432 glBindTexture(GL_TEXTURE_2D, surface->texture);
433 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
434 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
435 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
436 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
438 display_release_window_surface(nested->display, nested->window);
441 wl_resource_create(client, &wl_surface_interface, 1, id);
443 wl_resource_set_implementation(surface->resource,
444 &surface_interface, surface,
447 wl_list_insert(nested->surface_list.prev, &surface->link);
451 destroy_region(struct wl_resource *resource)
453 struct nested_region *region = wl_resource_get_user_data(resource);
455 pixman_region32_fini(®ion->region);
460 region_destroy(struct wl_client *client, struct wl_resource *resource)
462 wl_resource_destroy(resource);
466 region_add(struct wl_client *client, struct wl_resource *resource,
467 int32_t x, int32_t y, int32_t width, int32_t height)
469 struct nested_region *region = wl_resource_get_user_data(resource);
471 pixman_region32_union_rect(®ion->region, ®ion->region,
472 x, y, width, height);
476 region_subtract(struct wl_client *client, struct wl_resource *resource,
477 int32_t x, int32_t y, int32_t width, int32_t height)
479 struct nested_region *region = wl_resource_get_user_data(resource);
480 pixman_region32_t rect;
482 pixman_region32_init_rect(&rect, x, y, width, height);
483 pixman_region32_subtract(®ion->region, ®ion->region, &rect);
484 pixman_region32_fini(&rect);
487 static const struct wl_region_interface region_interface = {
494 compositor_create_region(struct wl_client *client,
495 struct wl_resource *resource, uint32_t id)
497 struct nested_region *region;
499 region = malloc(sizeof *region);
500 if (region == NULL) {
501 wl_resource_post_no_memory(resource);
505 pixman_region32_init(®ion->region);
508 wl_resource_create(client, &wl_region_interface, 1, id);
509 wl_resource_set_implementation(region->resource, ®ion_interface,
510 region, destroy_region);
513 static const struct wl_compositor_interface compositor_interface = {
514 compositor_create_surface,
515 compositor_create_region
519 compositor_bind(struct wl_client *client,
520 void *data, uint32_t version, uint32_t id)
522 struct nested *nested = data;
523 struct wl_resource *resource;
525 resource = wl_resource_create(client, &wl_compositor_interface,
526 MIN(version, 3), id);
527 wl_resource_set_implementation(resource, &compositor_interface,
532 nested_init_compositor(struct nested *nested)
534 const char *extensions;
535 struct wl_event_loop *loop;
538 wl_list_init(&nested->surface_list);
539 wl_list_init(&nested->frame_callback_list);
540 nested->child_display = wl_display_create();
541 loop = wl_display_get_event_loop(nested->child_display);
542 fd = wl_event_loop_get_fd(loop);
543 nested->child_task.run = handle_child_data;
544 display_watch_fd(nested->display, fd,
545 EPOLLIN, &nested->child_task);
547 if (!wl_global_create(nested->child_display,
548 &wl_compositor_interface, 1,
549 nested, compositor_bind))
552 wl_display_init_shm(nested->child_display);
554 nested->egl_display = display_get_egl_display(nested->display);
555 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
556 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
557 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
561 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
562 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
563 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
564 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
565 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
566 image_target_texture_2d =
567 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
569 ret = bind_display(nested->egl_display, nested->child_display);
571 fprintf(stderr, "failed to bind wl_display\n");
578 static struct nested *
579 nested_create(struct display *display)
581 struct nested *nested;
583 nested = zalloc(sizeof *nested);
587 nested->window = window_create(display);
588 nested->widget = window_frame_create(nested->window, nested);
589 window_set_title(nested->window, "Wayland Nested");
590 nested->display = display;
592 window_set_user_data(nested->window, nested);
593 widget_set_redraw_handler(nested->widget, redraw_handler);
594 window_set_keyboard_focus_handler(nested->window,
595 keyboard_focus_handler);
597 nested_init_compositor(nested);
599 widget_schedule_resize(nested->widget, 400, 400);
605 nested_destroy(struct nested *nested)
607 widget_destroy(nested->widget);
608 window_destroy(nested->window);
613 main(int argc, char *argv[])
615 struct display *display;
616 struct nested *nested;
618 display = display_create(&argc, argv);
619 if (display == NULL) {
620 fprintf(stderr, "failed to create display: %m\n");
624 nested = nested_create(display);
626 launch_client(nested, "weston-nested-client");
628 display_run(display);
630 nested_destroy(nested);
631 display_destroy(display);