blob: cf3a34e9e1252e9a21cc729944761b228a0bb481 [file] [log] [blame]
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001/*
2 * Copyright © 2013 Intel Corporation
3 *
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.
13 *
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
20 * OF THIS SOFTWARE.
21 */
22
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <cairo.h>
28#include <math.h>
29#include <assert.h>
30#include <pixman.h>
31#include <sys/epoll.h>
32#include <sys/socket.h>
33#include <unistd.h>
34
35#include <EGL/egl.h>
36#include <EGL/eglext.h>
37#include <GLES2/gl2.h>
38#include <GLES2/gl2ext.h>
39
40#include <cairo-gl.h>
41
42#include <wayland-client.h>
Kristian Høgsberg3c179332013-08-06 19:27:04 -070043#define WL_HIDE_DEPRECATED
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040044#include <wayland-server.h>
45
46#include "window.h"
47
Kristian Høgsberg919cddb2013-07-08 19:03:57 -040048#define MIN(x,y) (((x) < (y)) ? (x) : (y))
49
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040050struct nested {
51 struct display *display;
52 struct window *window;
53 struct widget *widget;
54 struct wl_display *child_display;
55 struct task child_task;
56
57 EGLDisplay egl_display;
58 struct program *texture_program;
59
60 struct wl_list surface_list;
61 struct wl_list frame_callback_list;
62};
63
64struct nested_region {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040065 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040066 pixman_region32_t region;
67};
68
Neil Roberts6bf23872013-09-08 18:49:15 +010069struct nested_buffer {
70 struct wl_resource *resource;
71 struct wl_signal destroy_signal;
72 struct wl_listener destroy_listener;
73 uint32_t busy_count;
74};
75
76struct nested_buffer_reference {
77 struct nested_buffer *buffer;
78 struct wl_listener destroy_listener;
79};
80
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040081struct nested_surface {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040082 struct wl_resource *resource;
Neil Roberts6bf23872013-09-08 18:49:15 +010083 struct nested_buffer_reference buffer_ref;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040084 struct nested *nested;
85 EGLImageKHR *image;
86 GLuint texture;
87 struct wl_list link;
88 cairo_surface_t *cairo_surface;
89};
90
91struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040092 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040093 struct wl_list link;
94};
95
96static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
97static PFNEGLCREATEIMAGEKHRPROC create_image;
98static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
99static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
100static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
101static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
102
103static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100104nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
105{
106 struct nested_buffer *buffer =
107 container_of(listener, struct nested_buffer, destroy_listener);
108
109 wl_signal_emit(&buffer->destroy_signal, buffer);
110 free(buffer);
111}
112
113static struct nested_buffer *
114nested_buffer_from_resource(struct wl_resource *resource)
115{
116 struct nested_buffer *buffer;
117 struct wl_listener *listener;
118
119 listener =
120 wl_resource_get_destroy_listener(resource,
121 nested_buffer_destroy_handler);
122
123 if (listener)
124 return container_of(listener, struct nested_buffer,
125 destroy_listener);
126
127 buffer = zalloc(sizeof *buffer);
128 if (buffer == NULL)
129 return NULL;
130
131 buffer->resource = resource;
132 wl_signal_init(&buffer->destroy_signal);
133 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
134 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
135
136 return buffer;
137}
138
139static void
140nested_buffer_reference_handle_destroy(struct wl_listener *listener,
141 void *data)
142{
143 struct nested_buffer_reference *ref =
144 container_of(listener, struct nested_buffer_reference,
145 destroy_listener);
146
147 assert((struct nested_buffer *)data == ref->buffer);
148 ref->buffer = NULL;
149}
150
151static void
152nested_buffer_reference(struct nested_buffer_reference *ref,
153 struct nested_buffer *buffer)
154{
155 if (buffer == ref->buffer)
156 return;
157
158 if (ref->buffer) {
159 ref->buffer->busy_count--;
160 if (ref->buffer->busy_count == 0) {
161 assert(wl_resource_get_client(ref->buffer->resource));
162 wl_resource_queue_event(ref->buffer->resource,
163 WL_BUFFER_RELEASE);
164 }
165 wl_list_remove(&ref->destroy_listener.link);
166 }
167
168 if (buffer) {
169 buffer->busy_count++;
170 wl_signal_add(&buffer->destroy_signal,
171 &ref->destroy_listener);
172
173 ref->destroy_listener.notify =
174 nested_buffer_reference_handle_destroy;
175 }
176
177 ref->buffer = buffer;
178}
179
180static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400181frame_callback(void *data, struct wl_callback *callback, uint32_t time)
182{
183 struct nested *nested = data;
184 struct nested_frame_callback *nc, *next;
185
186 if (callback)
187 wl_callback_destroy(callback);
188
189 wl_list_for_each_safe(nc, next, &nested->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400190 wl_callback_send_done(nc->resource, time);
191 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400192 }
193 wl_list_init(&nested->frame_callback_list);
194
195 /* FIXME: toytoolkit need a pre-block handler where we can
196 * call this. */
197 wl_display_flush_clients(nested->child_display);
198}
199
200static const struct wl_callback_listener frame_listener = {
201 frame_callback
202};
203
204static void
205redraw_handler(struct widget *widget, void *data)
206{
207 struct nested *nested = data;
208 cairo_surface_t *surface;
209 cairo_t *cr;
210 struct rectangle allocation;
211 struct wl_callback *callback;
212 struct nested_surface *s;
213
214 widget_get_allocation(nested->widget, &allocation);
215
216 surface = window_get_surface(nested->window);
217
218 cr = cairo_create(surface);
219 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
220 cairo_rectangle(cr,
221 allocation.x,
222 allocation.y,
223 allocation.width,
224 allocation.height);
225 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
226 cairo_fill(cr);
227
228 wl_list_for_each(s, &nested->surface_list, link) {
Ander Conselvan de Oliveirad224bb92013-07-16 14:24:04 +0300229 display_acquire_window_surface(nested->display,
230 nested->window, NULL);
231
232 glBindTexture(GL_TEXTURE_2D, s->texture);
233 image_target_texture_2d(GL_TEXTURE_2D, s->image);
234
235 display_release_window_surface(nested->display,
236 nested->window);
237
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400238 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
239 cairo_set_source_surface(cr, s->cairo_surface,
240 allocation.x + 10,
241 allocation.y + 10);
242 cairo_rectangle(cr, allocation.x + 10,
243 allocation.y + 10,
244 allocation.width - 10,
245 allocation.height - 10);
246
247 cairo_fill(cr);
248 }
249
250 cairo_destroy(cr);
251
252 cairo_surface_destroy(surface);
253
254 callback = wl_surface_frame(window_get_wl_surface(nested->window));
255 wl_callback_add_listener(callback, &frame_listener, nested);
256}
257
258static void
259keyboard_focus_handler(struct window *window,
260 struct input *device, void *data)
261{
262 struct nested *nested = data;
263
264 window_schedule_redraw(nested->window);
265}
266
267static void
268handle_child_data(struct task *task, uint32_t events)
269{
270 struct nested *nested = container_of(task, struct nested, child_task);
271 struct wl_event_loop *loop;
272
273 loop = wl_display_get_event_loop(nested->child_display);
274
275 wl_event_loop_dispatch(loop, -1);
276 wl_display_flush_clients(nested->child_display);
277}
278
279struct nested_client {
280 struct wl_client *client;
281 pid_t pid;
282};
283
284static struct nested_client *
285launch_client(struct nested *nested, const char *path)
286{
287 int sv[2];
288 pid_t pid;
289 struct nested_client *client;
290
291 client = malloc(sizeof *client);
292 if (client == NULL)
293 return NULL;
294
295 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
296 fprintf(stderr, "launch_client: "
297 "socketpair failed while launching '%s': %m\n",
298 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700299 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400300 return NULL;
301 }
302
303 pid = fork();
304 if (pid == -1) {
305 close(sv[0]);
306 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700307 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400308 fprintf(stderr, "launch_client: "
309 "fork failed while launching '%s': %m\n", path);
310 return NULL;
311 }
312
313 if (pid == 0) {
314 int clientfd;
315 char s[32];
316
317 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
318 * get a non-CLOEXEC fd to pass through exec. */
319 clientfd = dup(sv[1]);
320 if (clientfd == -1) {
321 fprintf(stderr, "compositor: dup failed: %m\n");
322 exit(-1);
323 }
324
325 snprintf(s, sizeof s, "%d", clientfd);
326 setenv("WAYLAND_SOCKET", s, 1);
327
328 execl(path, path, NULL);
329
330 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
331 path);
332 exit(-1);
333 }
334
335 close(sv[1]);
336
337 client->client = wl_client_create(nested->child_display, sv[0]);
338 if (!client->client) {
339 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700340 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400341 fprintf(stderr, "launch_client: "
342 "wl_client_create failed while launching '%s'.\n",
343 path);
344 return NULL;
345 }
346
347 client->pid = pid;
348
349 return client;
350}
351
352static void
353destroy_surface(struct wl_resource *resource)
354{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400355 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400356
Neil Roberts6bf23872013-09-08 18:49:15 +0100357 nested_buffer_reference(&surface->buffer_ref, NULL);
358
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000359 wl_list_remove(&surface->link);
360
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400361 free(surface);
362}
363
364static void
365surface_destroy(struct wl_client *client, struct wl_resource *resource)
366{
367 wl_resource_destroy(resource);
368}
369
370static void
371surface_attach(struct wl_client *client,
372 struct wl_resource *resource,
373 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
374{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400375 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400376 struct nested *nested = surface->nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400377 EGLint format, width, height;
378 cairo_device_t *device;
Neil Roberts6bf23872013-09-08 18:49:15 +0100379 struct nested_buffer *buffer =
380 nested_buffer_from_resource(buffer_resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400381
Neil Roberts6bf23872013-09-08 18:49:15 +0100382 nested_buffer_reference(&surface->buffer_ref, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400383
Kristian Høgsberge8344e32013-10-09 13:34:35 -0700384 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400385 EGL_TEXTURE_FORMAT, &format)) {
386 fprintf(stderr, "attaching non-egl wl_buffer\n");
387 return;
388 }
389
390 if (surface->image != EGL_NO_IMAGE_KHR)
391 destroy_image(nested->egl_display, surface->image);
392 if (surface->cairo_surface)
393 cairo_surface_destroy(surface->cairo_surface);
394
395 switch (format) {
396 case EGL_TEXTURE_RGB:
397 case EGL_TEXTURE_RGBA:
398 break;
399 default:
400 fprintf(stderr, "unhandled format: %x\n", format);
401 return;
402 }
403
404 surface->image = create_image(nested->egl_display, NULL,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700405 EGL_WAYLAND_BUFFER_WL, buffer_resource,
406 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400407 if (surface->image == EGL_NO_IMAGE_KHR) {
408 fprintf(stderr, "failed to create img\n");
409 return;
410 }
411
Kristian Høgsberge8344e32013-10-09 13:34:35 -0700412 query_buffer(nested->egl_display,
413 (void *) buffer_resource, EGL_WIDTH, &width);
414 query_buffer(nested->egl_display,
415 (void *) buffer_resource, EGL_HEIGHT, &height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400416
417 device = display_get_cairo_device(nested->display);
418 surface->cairo_surface =
419 cairo_gl_surface_create_for_texture(device,
420 CAIRO_CONTENT_COLOR_ALPHA,
421 surface->texture,
422 width, height);
423
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400424 window_schedule_redraw(nested->window);
425}
426
427static void
428surface_damage(struct wl_client *client,
429 struct wl_resource *resource,
430 int32_t x, int32_t y, int32_t width, int32_t height)
431{
432}
433
434static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400435destroy_frame_callback(struct wl_resource *resource)
436{
437 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
438
439 wl_list_remove(&callback->link);
440 free(callback);
441}
442
443static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400444surface_frame(struct wl_client *client,
445 struct wl_resource *resource, uint32_t id)
446{
447 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400448 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400449 struct nested *nested = surface->nested;
450
451 callback = malloc(sizeof *callback);
452 if (callback == NULL) {
453 wl_resource_post_no_memory(resource);
454 return;
455 }
456
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400457 callback->resource = wl_resource_create(client,
458 &wl_callback_interface, 1, id);
459 wl_resource_set_implementation(callback->resource, NULL, callback,
460 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400461
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400462 wl_list_insert(nested->frame_callback_list.prev, &callback->link);
463}
464
465static void
466surface_set_opaque_region(struct wl_client *client,
467 struct wl_resource *resource,
468 struct wl_resource *region_resource)
469{
470 fprintf(stderr, "surface_set_opaque_region\n");
471}
472
473static void
474surface_set_input_region(struct wl_client *client,
475 struct wl_resource *resource,
476 struct wl_resource *region_resource)
477{
478 fprintf(stderr, "surface_set_input_region\n");
479}
480
481static void
482surface_commit(struct wl_client *client, struct wl_resource *resource)
483{
484}
485
486static void
487surface_set_buffer_transform(struct wl_client *client,
488 struct wl_resource *resource, int transform)
489{
490 fprintf(stderr, "surface_set_buffer_transform\n");
491}
492
493static const struct wl_surface_interface surface_interface = {
494 surface_destroy,
495 surface_attach,
496 surface_damage,
497 surface_frame,
498 surface_set_opaque_region,
499 surface_set_input_region,
500 surface_commit,
501 surface_set_buffer_transform
502};
503
504static void
505compositor_create_surface(struct wl_client *client,
506 struct wl_resource *resource, uint32_t id)
507{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400508 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400509 struct nested_surface *surface;
510
Peter Huttererf3d62272013-08-08 11:57:05 +1000511 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400512 if (surface == NULL) {
513 wl_resource_post_no_memory(resource);
514 return;
515 }
516
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400517 surface->nested = nested;
518
519 display_acquire_window_surface(nested->display,
520 nested->window, NULL);
521
522 glGenTextures(1, &surface->texture);
523 glBindTexture(GL_TEXTURE_2D, surface->texture);
524 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
526 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
527 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
528
529 display_release_window_surface(nested->display, nested->window);
530
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400531 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400532 wl_resource_create(client, &wl_surface_interface, 1, id);
533
534 wl_resource_set_implementation(surface->resource,
535 &surface_interface, surface,
536 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400537
538 wl_list_insert(nested->surface_list.prev, &surface->link);
539}
540
541static void
542destroy_region(struct wl_resource *resource)
543{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400544 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400545
546 pixman_region32_fini(&region->region);
547 free(region);
548}
549
550static void
551region_destroy(struct wl_client *client, struct wl_resource *resource)
552{
553 wl_resource_destroy(resource);
554}
555
556static void
557region_add(struct wl_client *client, struct wl_resource *resource,
558 int32_t x, int32_t y, int32_t width, int32_t height)
559{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400560 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400561
562 pixman_region32_union_rect(&region->region, &region->region,
563 x, y, width, height);
564}
565
566static void
567region_subtract(struct wl_client *client, struct wl_resource *resource,
568 int32_t x, int32_t y, int32_t width, int32_t height)
569{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400570 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400571 pixman_region32_t rect;
572
573 pixman_region32_init_rect(&rect, x, y, width, height);
574 pixman_region32_subtract(&region->region, &region->region, &rect);
575 pixman_region32_fini(&rect);
576}
577
578static const struct wl_region_interface region_interface = {
579 region_destroy,
580 region_add,
581 region_subtract
582};
583
584static void
585compositor_create_region(struct wl_client *client,
586 struct wl_resource *resource, uint32_t id)
587{
588 struct nested_region *region;
589
590 region = malloc(sizeof *region);
591 if (region == NULL) {
592 wl_resource_post_no_memory(resource);
593 return;
594 }
595
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400596 pixman_region32_init(&region->region);
597
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400598 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400599 wl_resource_create(client, &wl_region_interface, 1, id);
600 wl_resource_set_implementation(region->resource, &region_interface,
601 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400602}
603
604static const struct wl_compositor_interface compositor_interface = {
605 compositor_create_surface,
606 compositor_create_region
607};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400608
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400609static void
610compositor_bind(struct wl_client *client,
611 void *data, uint32_t version, uint32_t id)
612{
613 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400614 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400615
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400616 resource = wl_resource_create(client, &wl_compositor_interface,
617 MIN(version, 3), id);
618 wl_resource_set_implementation(resource, &compositor_interface,
619 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400620}
621
622static int
623nested_init_compositor(struct nested *nested)
624{
625 const char *extensions;
626 struct wl_event_loop *loop;
627 int fd, ret;
628
629 wl_list_init(&nested->surface_list);
630 wl_list_init(&nested->frame_callback_list);
631 nested->child_display = wl_display_create();
632 loop = wl_display_get_event_loop(nested->child_display);
633 fd = wl_event_loop_get_fd(loop);
634 nested->child_task.run = handle_child_data;
635 display_watch_fd(nested->display, fd,
636 EPOLLIN, &nested->child_task);
637
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400638 if (!wl_global_create(nested->child_display,
639 &wl_compositor_interface, 1,
640 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400641 return -1;
642
643 wl_display_init_shm(nested->child_display);
644
645 nested->egl_display = display_get_egl_display(nested->display);
646 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
647 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
648 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
649 return -1;
650 }
651
652 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
653 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
654 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
655 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
656 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
657 image_target_texture_2d =
658 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
659
660 ret = bind_display(nested->egl_display, nested->child_display);
661 if (!ret) {
662 fprintf(stderr, "failed to bind wl_display\n");
663 return -1;
664 }
665
666 return 0;
667}
668
669static struct nested *
670nested_create(struct display *display)
671{
672 struct nested *nested;
673
Peter Huttererf3d62272013-08-08 11:57:05 +1000674 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400675 if (nested == NULL)
676 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400677
678 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500679 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400680 window_set_title(nested->window, "Wayland Nested");
681 nested->display = display;
682
683 window_set_user_data(nested->window, nested);
684 widget_set_redraw_handler(nested->widget, redraw_handler);
685 window_set_keyboard_focus_handler(nested->window,
686 keyboard_focus_handler);
687
688 nested_init_compositor(nested);
689
690 widget_schedule_resize(nested->widget, 400, 400);
691
692 return nested;
693}
694
695static void
696nested_destroy(struct nested *nested)
697{
698 widget_destroy(nested->widget);
699 window_destroy(nested->window);
700 free(nested);
701}
702
703int
704main(int argc, char *argv[])
705{
706 struct display *display;
707 struct nested *nested;
708
709 display = display_create(&argc, argv);
710 if (display == NULL) {
711 fprintf(stderr, "failed to create display: %m\n");
712 return -1;
713 }
714
715 nested = nested_create(display);
716
Kristian Høgsbergcb61dcf2013-08-07 09:50:12 -0700717 launch_client(nested, "weston-nested-client");
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400718
719 display_run(display);
720
721 nested_destroy(nested);
722 display_destroy(display);
723
724 return 0;
725}