blob: 23be0e31fd0f524457d6f5eae35cf8f24f723582 [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;
Neil Roberts15a8d342013-09-08 19:49:02 +010089
90 struct {
91 /* wl_surface.attach */
92 int newly_attached;
93 struct nested_buffer *buffer;
94 struct wl_listener buffer_destroy_listener;
95
96 /* wl_surface.frame */
97 struct wl_list frame_callback_list;
98 } pending;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040099};
100
101struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400102 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400103 struct wl_list link;
104};
105
106static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
107static PFNEGLCREATEIMAGEKHRPROC create_image;
108static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
109static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
110static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
111static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
112
113static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100114nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
115{
116 struct nested_buffer *buffer =
117 container_of(listener, struct nested_buffer, destroy_listener);
118
119 wl_signal_emit(&buffer->destroy_signal, buffer);
120 free(buffer);
121}
122
123static struct nested_buffer *
124nested_buffer_from_resource(struct wl_resource *resource)
125{
126 struct nested_buffer *buffer;
127 struct wl_listener *listener;
128
129 listener =
130 wl_resource_get_destroy_listener(resource,
131 nested_buffer_destroy_handler);
132
133 if (listener)
134 return container_of(listener, struct nested_buffer,
135 destroy_listener);
136
137 buffer = zalloc(sizeof *buffer);
138 if (buffer == NULL)
139 return NULL;
140
141 buffer->resource = resource;
142 wl_signal_init(&buffer->destroy_signal);
143 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
144 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
145
146 return buffer;
147}
148
149static void
150nested_buffer_reference_handle_destroy(struct wl_listener *listener,
151 void *data)
152{
153 struct nested_buffer_reference *ref =
154 container_of(listener, struct nested_buffer_reference,
155 destroy_listener);
156
157 assert((struct nested_buffer *)data == ref->buffer);
158 ref->buffer = NULL;
159}
160
161static void
162nested_buffer_reference(struct nested_buffer_reference *ref,
163 struct nested_buffer *buffer)
164{
165 if (buffer == ref->buffer)
166 return;
167
168 if (ref->buffer) {
169 ref->buffer->busy_count--;
170 if (ref->buffer->busy_count == 0) {
171 assert(wl_resource_get_client(ref->buffer->resource));
172 wl_resource_queue_event(ref->buffer->resource,
173 WL_BUFFER_RELEASE);
174 }
175 wl_list_remove(&ref->destroy_listener.link);
176 }
177
178 if (buffer) {
179 buffer->busy_count++;
180 wl_signal_add(&buffer->destroy_signal,
181 &ref->destroy_listener);
182
183 ref->destroy_listener.notify =
184 nested_buffer_reference_handle_destroy;
185 }
186
187 ref->buffer = buffer;
188}
189
190static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400191frame_callback(void *data, struct wl_callback *callback, uint32_t time)
192{
193 struct nested *nested = data;
194 struct nested_frame_callback *nc, *next;
195
196 if (callback)
197 wl_callback_destroy(callback);
198
199 wl_list_for_each_safe(nc, next, &nested->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400200 wl_callback_send_done(nc->resource, time);
201 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400202 }
203 wl_list_init(&nested->frame_callback_list);
204
205 /* FIXME: toytoolkit need a pre-block handler where we can
206 * call this. */
207 wl_display_flush_clients(nested->child_display);
208}
209
210static const struct wl_callback_listener frame_listener = {
211 frame_callback
212};
213
214static void
215redraw_handler(struct widget *widget, void *data)
216{
217 struct nested *nested = data;
218 cairo_surface_t *surface;
219 cairo_t *cr;
220 struct rectangle allocation;
221 struct wl_callback *callback;
222 struct nested_surface *s;
223
224 widget_get_allocation(nested->widget, &allocation);
225
226 surface = window_get_surface(nested->window);
227
228 cr = cairo_create(surface);
229 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
230 cairo_rectangle(cr,
231 allocation.x,
232 allocation.y,
233 allocation.width,
234 allocation.height);
235 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
236 cairo_fill(cr);
237
238 wl_list_for_each(s, &nested->surface_list, link) {
Ander Conselvan de Oliveirad224bb92013-07-16 14:24:04 +0300239 display_acquire_window_surface(nested->display,
240 nested->window, NULL);
241
242 glBindTexture(GL_TEXTURE_2D, s->texture);
243 image_target_texture_2d(GL_TEXTURE_2D, s->image);
244
245 display_release_window_surface(nested->display,
246 nested->window);
247
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400248 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
249 cairo_set_source_surface(cr, s->cairo_surface,
250 allocation.x + 10,
251 allocation.y + 10);
252 cairo_rectangle(cr, allocation.x + 10,
253 allocation.y + 10,
254 allocation.width - 10,
255 allocation.height - 10);
256
257 cairo_fill(cr);
258 }
259
260 cairo_destroy(cr);
261
262 cairo_surface_destroy(surface);
263
264 callback = wl_surface_frame(window_get_wl_surface(nested->window));
265 wl_callback_add_listener(callback, &frame_listener, nested);
266}
267
268static void
269keyboard_focus_handler(struct window *window,
270 struct input *device, void *data)
271{
272 struct nested *nested = data;
273
274 window_schedule_redraw(nested->window);
275}
276
277static void
278handle_child_data(struct task *task, uint32_t events)
279{
280 struct nested *nested = container_of(task, struct nested, child_task);
281 struct wl_event_loop *loop;
282
283 loop = wl_display_get_event_loop(nested->child_display);
284
285 wl_event_loop_dispatch(loop, -1);
286 wl_display_flush_clients(nested->child_display);
287}
288
289struct nested_client {
290 struct wl_client *client;
291 pid_t pid;
292};
293
294static struct nested_client *
295launch_client(struct nested *nested, const char *path)
296{
297 int sv[2];
298 pid_t pid;
299 struct nested_client *client;
300
301 client = malloc(sizeof *client);
302 if (client == NULL)
303 return NULL;
304
305 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
306 fprintf(stderr, "launch_client: "
307 "socketpair failed while launching '%s': %m\n",
308 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700309 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400310 return NULL;
311 }
312
313 pid = fork();
314 if (pid == -1) {
315 close(sv[0]);
316 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700317 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400318 fprintf(stderr, "launch_client: "
319 "fork failed while launching '%s': %m\n", path);
320 return NULL;
321 }
322
323 if (pid == 0) {
324 int clientfd;
325 char s[32];
326
327 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
328 * get a non-CLOEXEC fd to pass through exec. */
329 clientfd = dup(sv[1]);
330 if (clientfd == -1) {
331 fprintf(stderr, "compositor: dup failed: %m\n");
332 exit(-1);
333 }
334
335 snprintf(s, sizeof s, "%d", clientfd);
336 setenv("WAYLAND_SOCKET", s, 1);
337
338 execl(path, path, NULL);
339
340 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
341 path);
342 exit(-1);
343 }
344
345 close(sv[1]);
346
347 client->client = wl_client_create(nested->child_display, sv[0]);
348 if (!client->client) {
349 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700350 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400351 fprintf(stderr, "launch_client: "
352 "wl_client_create failed while launching '%s'.\n",
353 path);
354 return NULL;
355 }
356
357 client->pid = pid;
358
359 return client;
360}
361
362static void
363destroy_surface(struct wl_resource *resource)
364{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400365 struct nested_surface *surface = wl_resource_get_user_data(resource);
Neil Roberts15a8d342013-09-08 19:49:02 +0100366 struct nested_frame_callback *cb, *next;
367
368 wl_list_for_each_safe(cb, next,
369 &surface->pending.frame_callback_list, link)
370 wl_resource_destroy(cb->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400371
Neil Roberts6bf23872013-09-08 18:49:15 +0100372 nested_buffer_reference(&surface->buffer_ref, NULL);
373
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000374 wl_list_remove(&surface->link);
375
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400376 free(surface);
377}
378
379static void
380surface_destroy(struct wl_client *client, struct wl_resource *resource)
381{
382 wl_resource_destroy(resource);
383}
384
385static void
386surface_attach(struct wl_client *client,
387 struct wl_resource *resource,
388 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
389{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400390 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400391 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100392 struct nested_buffer *buffer = NULL;
393
394 if (buffer_resource) {
395 int format;
396
397 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
398 EGL_TEXTURE_FORMAT, &format)) {
399 wl_resource_post_error(buffer_resource,
400 WL_DISPLAY_ERROR_INVALID_OBJECT,
401 "attaching non-egl wl_buffer");
402 return;
403 }
404
405 switch (format) {
406 case EGL_TEXTURE_RGB:
407 case EGL_TEXTURE_RGBA:
408 break;
409 default:
410 wl_resource_post_error(buffer_resource,
411 WL_DISPLAY_ERROR_INVALID_OBJECT,
412 "invalid format");
413 return;
414 }
415
416 buffer = nested_buffer_from_resource(buffer_resource);
417 if (buffer == NULL) {
418 wl_client_post_no_memory(client);
419 return;
420 }
421 }
422
423 if (surface->pending.buffer)
424 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
425
426 surface->pending.buffer = buffer;
427 surface->pending.newly_attached = 1;
428 if (buffer) {
429 wl_signal_add(&buffer->destroy_signal,
430 &surface->pending.buffer_destroy_listener);
431 }
432}
433
434static void
435nested_surface_attach(struct nested_surface *surface,
436 struct nested_buffer *buffer)
437{
438 struct nested *nested = surface->nested;
439 EGLint width, height;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400440 cairo_device_t *device;
441
Neil Roberts6bf23872013-09-08 18:49:15 +0100442 nested_buffer_reference(&surface->buffer_ref, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400443
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400444 if (surface->image != EGL_NO_IMAGE_KHR)
445 destroy_image(nested->egl_display, surface->image);
446 if (surface->cairo_surface)
447 cairo_surface_destroy(surface->cairo_surface);
448
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400449 surface->image = create_image(nested->egl_display, NULL,
Neil Roberts15a8d342013-09-08 19:49:02 +0100450 EGL_WAYLAND_BUFFER_WL, buffer->resource,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700451 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400452 if (surface->image == EGL_NO_IMAGE_KHR) {
453 fprintf(stderr, "failed to create img\n");
454 return;
455 }
456
Neil Roberts15a8d342013-09-08 19:49:02 +0100457 query_buffer(nested->egl_display, (void *) buffer->resource,
458 EGL_WIDTH, &width);
459 query_buffer(nested->egl_display, (void *) buffer->resource,
460 EGL_HEIGHT, &height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400461
462 device = display_get_cairo_device(nested->display);
463 surface->cairo_surface =
464 cairo_gl_surface_create_for_texture(device,
465 CAIRO_CONTENT_COLOR_ALPHA,
466 surface->texture,
467 width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400468}
469
470static void
471surface_damage(struct wl_client *client,
472 struct wl_resource *resource,
473 int32_t x, int32_t y, int32_t width, int32_t height)
474{
475}
476
477static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400478destroy_frame_callback(struct wl_resource *resource)
479{
480 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
481
482 wl_list_remove(&callback->link);
483 free(callback);
484}
485
486static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400487surface_frame(struct wl_client *client,
488 struct wl_resource *resource, uint32_t id)
489{
490 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400491 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400492
493 callback = malloc(sizeof *callback);
494 if (callback == NULL) {
495 wl_resource_post_no_memory(resource);
496 return;
497 }
498
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400499 callback->resource = wl_resource_create(client,
500 &wl_callback_interface, 1, id);
501 wl_resource_set_implementation(callback->resource, NULL, callback,
502 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400503
Neil Roberts15a8d342013-09-08 19:49:02 +0100504 wl_list_insert(surface->pending.frame_callback_list.prev,
505 &callback->link);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400506}
507
508static void
509surface_set_opaque_region(struct wl_client *client,
510 struct wl_resource *resource,
511 struct wl_resource *region_resource)
512{
513 fprintf(stderr, "surface_set_opaque_region\n");
514}
515
516static void
517surface_set_input_region(struct wl_client *client,
518 struct wl_resource *resource,
519 struct wl_resource *region_resource)
520{
521 fprintf(stderr, "surface_set_input_region\n");
522}
523
524static void
525surface_commit(struct wl_client *client, struct wl_resource *resource)
526{
Neil Roberts15a8d342013-09-08 19:49:02 +0100527 struct nested_surface *surface = wl_resource_get_user_data(resource);
528 struct nested *nested = surface->nested;
529
530 /* wl_surface.attach */
531 if (surface->pending.newly_attached)
532 nested_surface_attach(surface, surface->pending.buffer);
533
534 if (surface->pending.buffer) {
535 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
536 surface->pending.buffer = NULL;
537 }
538 surface->pending.newly_attached = 0;
539
540 /* wl_surface.frame */
541 wl_list_insert_list(&nested->frame_callback_list,
542 &surface->pending.frame_callback_list);
543 wl_list_init(&surface->pending.frame_callback_list);
544
545 window_schedule_redraw(nested->window);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400546}
547
548static void
549surface_set_buffer_transform(struct wl_client *client,
550 struct wl_resource *resource, int transform)
551{
552 fprintf(stderr, "surface_set_buffer_transform\n");
553}
554
555static const struct wl_surface_interface surface_interface = {
556 surface_destroy,
557 surface_attach,
558 surface_damage,
559 surface_frame,
560 surface_set_opaque_region,
561 surface_set_input_region,
562 surface_commit,
563 surface_set_buffer_transform
564};
565
566static void
Neil Roberts15a8d342013-09-08 19:49:02 +0100567surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
568{
569 struct nested_surface *surface =
570 container_of(listener, struct nested_surface,
571 pending.buffer_destroy_listener);
572
573 surface->pending.buffer = NULL;
574}
575
576static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400577compositor_create_surface(struct wl_client *client,
578 struct wl_resource *resource, uint32_t id)
579{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400580 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400581 struct nested_surface *surface;
582
Peter Huttererf3d62272013-08-08 11:57:05 +1000583 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400584 if (surface == NULL) {
585 wl_resource_post_no_memory(resource);
586 return;
587 }
588
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400589 surface->nested = nested;
590
Neil Roberts15a8d342013-09-08 19:49:02 +0100591 wl_list_init(&surface->pending.frame_callback_list);
592 surface->pending.buffer_destroy_listener.notify =
593 surface_handle_pending_buffer_destroy;
594
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400595 display_acquire_window_surface(nested->display,
596 nested->window, NULL);
597
598 glGenTextures(1, &surface->texture);
599 glBindTexture(GL_TEXTURE_2D, surface->texture);
600 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
602 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
603 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
604
605 display_release_window_surface(nested->display, nested->window);
606
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400607 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400608 wl_resource_create(client, &wl_surface_interface, 1, id);
609
610 wl_resource_set_implementation(surface->resource,
611 &surface_interface, surface,
612 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400613
614 wl_list_insert(nested->surface_list.prev, &surface->link);
615}
616
617static void
618destroy_region(struct wl_resource *resource)
619{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400620 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400621
622 pixman_region32_fini(&region->region);
623 free(region);
624}
625
626static void
627region_destroy(struct wl_client *client, struct wl_resource *resource)
628{
629 wl_resource_destroy(resource);
630}
631
632static void
633region_add(struct wl_client *client, struct wl_resource *resource,
634 int32_t x, int32_t y, int32_t width, int32_t height)
635{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400636 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400637
638 pixman_region32_union_rect(&region->region, &region->region,
639 x, y, width, height);
640}
641
642static void
643region_subtract(struct wl_client *client, struct wl_resource *resource,
644 int32_t x, int32_t y, int32_t width, int32_t height)
645{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400646 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400647 pixman_region32_t rect;
648
649 pixman_region32_init_rect(&rect, x, y, width, height);
650 pixman_region32_subtract(&region->region, &region->region, &rect);
651 pixman_region32_fini(&rect);
652}
653
654static const struct wl_region_interface region_interface = {
655 region_destroy,
656 region_add,
657 region_subtract
658};
659
660static void
661compositor_create_region(struct wl_client *client,
662 struct wl_resource *resource, uint32_t id)
663{
664 struct nested_region *region;
665
666 region = malloc(sizeof *region);
667 if (region == NULL) {
668 wl_resource_post_no_memory(resource);
669 return;
670 }
671
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400672 pixman_region32_init(&region->region);
673
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400674 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400675 wl_resource_create(client, &wl_region_interface, 1, id);
676 wl_resource_set_implementation(region->resource, &region_interface,
677 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400678}
679
680static const struct wl_compositor_interface compositor_interface = {
681 compositor_create_surface,
682 compositor_create_region
683};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400684
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400685static void
686compositor_bind(struct wl_client *client,
687 void *data, uint32_t version, uint32_t id)
688{
689 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400690 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400691
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400692 resource = wl_resource_create(client, &wl_compositor_interface,
693 MIN(version, 3), id);
694 wl_resource_set_implementation(resource, &compositor_interface,
695 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400696}
697
698static int
699nested_init_compositor(struct nested *nested)
700{
701 const char *extensions;
702 struct wl_event_loop *loop;
703 int fd, ret;
704
705 wl_list_init(&nested->surface_list);
706 wl_list_init(&nested->frame_callback_list);
707 nested->child_display = wl_display_create();
708 loop = wl_display_get_event_loop(nested->child_display);
709 fd = wl_event_loop_get_fd(loop);
710 nested->child_task.run = handle_child_data;
711 display_watch_fd(nested->display, fd,
712 EPOLLIN, &nested->child_task);
713
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400714 if (!wl_global_create(nested->child_display,
715 &wl_compositor_interface, 1,
716 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400717 return -1;
718
719 wl_display_init_shm(nested->child_display);
720
721 nested->egl_display = display_get_egl_display(nested->display);
722 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
723 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
724 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
725 return -1;
726 }
727
728 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
729 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
730 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
731 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
732 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
733 image_target_texture_2d =
734 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
735
736 ret = bind_display(nested->egl_display, nested->child_display);
737 if (!ret) {
738 fprintf(stderr, "failed to bind wl_display\n");
739 return -1;
740 }
741
742 return 0;
743}
744
745static struct nested *
746nested_create(struct display *display)
747{
748 struct nested *nested;
749
Peter Huttererf3d62272013-08-08 11:57:05 +1000750 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400751 if (nested == NULL)
752 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400753
754 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500755 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400756 window_set_title(nested->window, "Wayland Nested");
757 nested->display = display;
758
759 window_set_user_data(nested->window, nested);
760 widget_set_redraw_handler(nested->widget, redraw_handler);
761 window_set_keyboard_focus_handler(nested->window,
762 keyboard_focus_handler);
763
764 nested_init_compositor(nested);
765
766 widget_schedule_resize(nested->widget, 400, 400);
767
768 return nested;
769}
770
771static void
772nested_destroy(struct nested *nested)
773{
774 widget_destroy(nested->widget);
775 window_destroy(nested->window);
776 free(nested);
777}
778
779int
780main(int argc, char *argv[])
781{
782 struct display *display;
783 struct nested *nested;
784
785 display = display_create(&argc, argv);
786 if (display == NULL) {
787 fprintf(stderr, "failed to create display: %m\n");
788 return -1;
789 }
790
791 nested = nested_create(display);
792
Kristian Høgsbergcb61dcf2013-08-07 09:50:12 -0700793 launch_client(nested, "weston-nested-client");
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400794
795 display_run(display);
796
797 nested_destroy(nested);
798 display_destroy(display);
799
800 return 0;
801}