blob: b2f594993990bde7a4ce7157e4fdd802d3130a65 [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;
Neil Roberts28557662013-09-08 20:24:14 +010098
99 /* wl_surface.damage */
100 pixman_region32_t damage;
Neil Roberts15a8d342013-09-08 19:49:02 +0100101 } pending;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400102};
103
104struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400105 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400106 struct wl_list link;
107};
108
109static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
110static PFNEGLCREATEIMAGEKHRPROC create_image;
111static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
112static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
113static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
114static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
115
116static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100117nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
118{
119 struct nested_buffer *buffer =
120 container_of(listener, struct nested_buffer, destroy_listener);
121
122 wl_signal_emit(&buffer->destroy_signal, buffer);
123 free(buffer);
124}
125
126static struct nested_buffer *
127nested_buffer_from_resource(struct wl_resource *resource)
128{
129 struct nested_buffer *buffer;
130 struct wl_listener *listener;
131
132 listener =
133 wl_resource_get_destroy_listener(resource,
134 nested_buffer_destroy_handler);
135
136 if (listener)
137 return container_of(listener, struct nested_buffer,
138 destroy_listener);
139
140 buffer = zalloc(sizeof *buffer);
141 if (buffer == NULL)
142 return NULL;
143
144 buffer->resource = resource;
145 wl_signal_init(&buffer->destroy_signal);
146 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
147 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
148
149 return buffer;
150}
151
152static void
153nested_buffer_reference_handle_destroy(struct wl_listener *listener,
154 void *data)
155{
156 struct nested_buffer_reference *ref =
157 container_of(listener, struct nested_buffer_reference,
158 destroy_listener);
159
160 assert((struct nested_buffer *)data == ref->buffer);
161 ref->buffer = NULL;
162}
163
164static void
165nested_buffer_reference(struct nested_buffer_reference *ref,
166 struct nested_buffer *buffer)
167{
168 if (buffer == ref->buffer)
169 return;
170
171 if (ref->buffer) {
172 ref->buffer->busy_count--;
173 if (ref->buffer->busy_count == 0) {
174 assert(wl_resource_get_client(ref->buffer->resource));
175 wl_resource_queue_event(ref->buffer->resource,
176 WL_BUFFER_RELEASE);
177 }
178 wl_list_remove(&ref->destroy_listener.link);
179 }
180
181 if (buffer) {
182 buffer->busy_count++;
183 wl_signal_add(&buffer->destroy_signal,
184 &ref->destroy_listener);
185
186 ref->destroy_listener.notify =
187 nested_buffer_reference_handle_destroy;
188 }
189
190 ref->buffer = buffer;
191}
192
193static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400194frame_callback(void *data, struct wl_callback *callback, uint32_t time)
195{
196 struct nested *nested = data;
197 struct nested_frame_callback *nc, *next;
198
199 if (callback)
200 wl_callback_destroy(callback);
201
202 wl_list_for_each_safe(nc, next, &nested->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400203 wl_callback_send_done(nc->resource, time);
204 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400205 }
206 wl_list_init(&nested->frame_callback_list);
207
208 /* FIXME: toytoolkit need a pre-block handler where we can
209 * call this. */
210 wl_display_flush_clients(nested->child_display);
211}
212
213static const struct wl_callback_listener frame_listener = {
214 frame_callback
215};
216
217static void
218redraw_handler(struct widget *widget, void *data)
219{
220 struct nested *nested = data;
221 cairo_surface_t *surface;
222 cairo_t *cr;
223 struct rectangle allocation;
224 struct wl_callback *callback;
225 struct nested_surface *s;
226
227 widget_get_allocation(nested->widget, &allocation);
228
229 surface = window_get_surface(nested->window);
230
231 cr = cairo_create(surface);
232 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
233 cairo_rectangle(cr,
234 allocation.x,
235 allocation.y,
236 allocation.width,
237 allocation.height);
238 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
239 cairo_fill(cr);
240
241 wl_list_for_each(s, &nested->surface_list, link) {
Ander Conselvan de Oliveirad224bb92013-07-16 14:24:04 +0300242 display_acquire_window_surface(nested->display,
243 nested->window, NULL);
244
245 glBindTexture(GL_TEXTURE_2D, s->texture);
246 image_target_texture_2d(GL_TEXTURE_2D, s->image);
247
248 display_release_window_surface(nested->display,
249 nested->window);
250
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400251 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
252 cairo_set_source_surface(cr, s->cairo_surface,
253 allocation.x + 10,
254 allocation.y + 10);
255 cairo_rectangle(cr, allocation.x + 10,
256 allocation.y + 10,
257 allocation.width - 10,
258 allocation.height - 10);
259
260 cairo_fill(cr);
261 }
262
263 cairo_destroy(cr);
264
265 cairo_surface_destroy(surface);
266
267 callback = wl_surface_frame(window_get_wl_surface(nested->window));
268 wl_callback_add_listener(callback, &frame_listener, nested);
269}
270
271static void
272keyboard_focus_handler(struct window *window,
273 struct input *device, void *data)
274{
275 struct nested *nested = data;
276
277 window_schedule_redraw(nested->window);
278}
279
280static void
281handle_child_data(struct task *task, uint32_t events)
282{
283 struct nested *nested = container_of(task, struct nested, child_task);
284 struct wl_event_loop *loop;
285
286 loop = wl_display_get_event_loop(nested->child_display);
287
288 wl_event_loop_dispatch(loop, -1);
289 wl_display_flush_clients(nested->child_display);
290}
291
292struct nested_client {
293 struct wl_client *client;
294 pid_t pid;
295};
296
297static struct nested_client *
298launch_client(struct nested *nested, const char *path)
299{
300 int sv[2];
301 pid_t pid;
302 struct nested_client *client;
303
304 client = malloc(sizeof *client);
305 if (client == NULL)
306 return NULL;
307
308 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
309 fprintf(stderr, "launch_client: "
310 "socketpair failed while launching '%s': %m\n",
311 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700312 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400313 return NULL;
314 }
315
316 pid = fork();
317 if (pid == -1) {
318 close(sv[0]);
319 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700320 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400321 fprintf(stderr, "launch_client: "
322 "fork failed while launching '%s': %m\n", path);
323 return NULL;
324 }
325
326 if (pid == 0) {
327 int clientfd;
328 char s[32];
329
330 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
331 * get a non-CLOEXEC fd to pass through exec. */
332 clientfd = dup(sv[1]);
333 if (clientfd == -1) {
334 fprintf(stderr, "compositor: dup failed: %m\n");
335 exit(-1);
336 }
337
338 snprintf(s, sizeof s, "%d", clientfd);
339 setenv("WAYLAND_SOCKET", s, 1);
340
341 execl(path, path, NULL);
342
343 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
344 path);
345 exit(-1);
346 }
347
348 close(sv[1]);
349
350 client->client = wl_client_create(nested->child_display, sv[0]);
351 if (!client->client) {
352 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700353 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400354 fprintf(stderr, "launch_client: "
355 "wl_client_create failed while launching '%s'.\n",
356 path);
357 return NULL;
358 }
359
360 client->pid = pid;
361
362 return client;
363}
364
365static void
366destroy_surface(struct wl_resource *resource)
367{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400368 struct nested_surface *surface = wl_resource_get_user_data(resource);
Neil Roberts15a8d342013-09-08 19:49:02 +0100369 struct nested_frame_callback *cb, *next;
370
371 wl_list_for_each_safe(cb, next,
372 &surface->pending.frame_callback_list, link)
373 wl_resource_destroy(cb->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400374
Neil Roberts6bf23872013-09-08 18:49:15 +0100375 nested_buffer_reference(&surface->buffer_ref, NULL);
376
Neil Roberts28557662013-09-08 20:24:14 +0100377 pixman_region32_fini(&surface->pending.damage);
378
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000379 wl_list_remove(&surface->link);
380
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400381 free(surface);
382}
383
384static void
385surface_destroy(struct wl_client *client, struct wl_resource *resource)
386{
387 wl_resource_destroy(resource);
388}
389
390static void
391surface_attach(struct wl_client *client,
392 struct wl_resource *resource,
393 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
394{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400395 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400396 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100397 struct nested_buffer *buffer = NULL;
398
399 if (buffer_resource) {
400 int format;
401
402 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
403 EGL_TEXTURE_FORMAT, &format)) {
404 wl_resource_post_error(buffer_resource,
405 WL_DISPLAY_ERROR_INVALID_OBJECT,
406 "attaching non-egl wl_buffer");
407 return;
408 }
409
410 switch (format) {
411 case EGL_TEXTURE_RGB:
412 case EGL_TEXTURE_RGBA:
413 break;
414 default:
415 wl_resource_post_error(buffer_resource,
416 WL_DISPLAY_ERROR_INVALID_OBJECT,
417 "invalid format");
418 return;
419 }
420
421 buffer = nested_buffer_from_resource(buffer_resource);
422 if (buffer == NULL) {
423 wl_client_post_no_memory(client);
424 return;
425 }
426 }
427
428 if (surface->pending.buffer)
429 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
430
431 surface->pending.buffer = buffer;
432 surface->pending.newly_attached = 1;
433 if (buffer) {
434 wl_signal_add(&buffer->destroy_signal,
435 &surface->pending.buffer_destroy_listener);
436 }
437}
438
439static void
440nested_surface_attach(struct nested_surface *surface,
441 struct nested_buffer *buffer)
442{
443 struct nested *nested = surface->nested;
444 EGLint width, height;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400445 cairo_device_t *device;
446
Neil Roberts6bf23872013-09-08 18:49:15 +0100447 nested_buffer_reference(&surface->buffer_ref, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400448
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400449 if (surface->image != EGL_NO_IMAGE_KHR)
450 destroy_image(nested->egl_display, surface->image);
451 if (surface->cairo_surface)
452 cairo_surface_destroy(surface->cairo_surface);
453
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400454 surface->image = create_image(nested->egl_display, NULL,
Neil Roberts15a8d342013-09-08 19:49:02 +0100455 EGL_WAYLAND_BUFFER_WL, buffer->resource,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700456 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400457 if (surface->image == EGL_NO_IMAGE_KHR) {
458 fprintf(stderr, "failed to create img\n");
459 return;
460 }
461
Neil Roberts15a8d342013-09-08 19:49:02 +0100462 query_buffer(nested->egl_display, (void *) buffer->resource,
463 EGL_WIDTH, &width);
464 query_buffer(nested->egl_display, (void *) buffer->resource,
465 EGL_HEIGHT, &height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400466
467 device = display_get_cairo_device(nested->display);
468 surface->cairo_surface =
469 cairo_gl_surface_create_for_texture(device,
470 CAIRO_CONTENT_COLOR_ALPHA,
471 surface->texture,
472 width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400473}
474
475static void
476surface_damage(struct wl_client *client,
477 struct wl_resource *resource,
478 int32_t x, int32_t y, int32_t width, int32_t height)
479{
Neil Roberts28557662013-09-08 20:24:14 +0100480 struct nested_surface *surface = wl_resource_get_user_data(resource);
481
482 pixman_region32_union_rect(&surface->pending.damage,
483 &surface->pending.damage,
484 x, y, width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400485}
486
487static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400488destroy_frame_callback(struct wl_resource *resource)
489{
490 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
491
492 wl_list_remove(&callback->link);
493 free(callback);
494}
495
496static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400497surface_frame(struct wl_client *client,
498 struct wl_resource *resource, uint32_t id)
499{
500 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400501 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400502
503 callback = malloc(sizeof *callback);
504 if (callback == NULL) {
505 wl_resource_post_no_memory(resource);
506 return;
507 }
508
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400509 callback->resource = wl_resource_create(client,
510 &wl_callback_interface, 1, id);
511 wl_resource_set_implementation(callback->resource, NULL, callback,
512 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400513
Neil Roberts15a8d342013-09-08 19:49:02 +0100514 wl_list_insert(surface->pending.frame_callback_list.prev,
515 &callback->link);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400516}
517
518static void
519surface_set_opaque_region(struct wl_client *client,
520 struct wl_resource *resource,
521 struct wl_resource *region_resource)
522{
523 fprintf(stderr, "surface_set_opaque_region\n");
524}
525
526static void
527surface_set_input_region(struct wl_client *client,
528 struct wl_resource *resource,
529 struct wl_resource *region_resource)
530{
531 fprintf(stderr, "surface_set_input_region\n");
532}
533
534static void
Neil Roberts28557662013-09-08 20:24:14 +0100535empty_region(pixman_region32_t *region)
536{
537 pixman_region32_fini(region);
538 pixman_region32_init(region);
539}
540
541static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400542surface_commit(struct wl_client *client, struct wl_resource *resource)
543{
Neil Roberts15a8d342013-09-08 19:49:02 +0100544 struct nested_surface *surface = wl_resource_get_user_data(resource);
545 struct nested *nested = surface->nested;
546
547 /* wl_surface.attach */
548 if (surface->pending.newly_attached)
549 nested_surface_attach(surface, surface->pending.buffer);
550
551 if (surface->pending.buffer) {
552 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
553 surface->pending.buffer = NULL;
554 }
555 surface->pending.newly_attached = 0;
556
Neil Roberts28557662013-09-08 20:24:14 +0100557 /* wl_surface.damage */
558 empty_region(&surface->pending.damage);
559
Neil Roberts15a8d342013-09-08 19:49:02 +0100560 /* wl_surface.frame */
561 wl_list_insert_list(&nested->frame_callback_list,
562 &surface->pending.frame_callback_list);
563 wl_list_init(&surface->pending.frame_callback_list);
564
565 window_schedule_redraw(nested->window);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400566}
567
568static void
569surface_set_buffer_transform(struct wl_client *client,
570 struct wl_resource *resource, int transform)
571{
572 fprintf(stderr, "surface_set_buffer_transform\n");
573}
574
575static const struct wl_surface_interface surface_interface = {
576 surface_destroy,
577 surface_attach,
578 surface_damage,
579 surface_frame,
580 surface_set_opaque_region,
581 surface_set_input_region,
582 surface_commit,
583 surface_set_buffer_transform
584};
585
586static void
Neil Roberts15a8d342013-09-08 19:49:02 +0100587surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
588{
589 struct nested_surface *surface =
590 container_of(listener, struct nested_surface,
591 pending.buffer_destroy_listener);
592
593 surface->pending.buffer = NULL;
594}
595
596static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400597compositor_create_surface(struct wl_client *client,
598 struct wl_resource *resource, uint32_t id)
599{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400600 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400601 struct nested_surface *surface;
602
Peter Huttererf3d62272013-08-08 11:57:05 +1000603 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400604 if (surface == NULL) {
605 wl_resource_post_no_memory(resource);
606 return;
607 }
608
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400609 surface->nested = nested;
610
Neil Roberts15a8d342013-09-08 19:49:02 +0100611 wl_list_init(&surface->pending.frame_callback_list);
612 surface->pending.buffer_destroy_listener.notify =
613 surface_handle_pending_buffer_destroy;
Neil Roberts28557662013-09-08 20:24:14 +0100614 pixman_region32_init(&surface->pending.damage);
Neil Roberts15a8d342013-09-08 19:49:02 +0100615
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400616 display_acquire_window_surface(nested->display,
617 nested->window, NULL);
618
619 glGenTextures(1, &surface->texture);
620 glBindTexture(GL_TEXTURE_2D, surface->texture);
621 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
622 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
623 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
624 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
625
626 display_release_window_surface(nested->display, nested->window);
627
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400628 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400629 wl_resource_create(client, &wl_surface_interface, 1, id);
630
631 wl_resource_set_implementation(surface->resource,
632 &surface_interface, surface,
633 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400634
635 wl_list_insert(nested->surface_list.prev, &surface->link);
636}
637
638static void
639destroy_region(struct wl_resource *resource)
640{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400641 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400642
643 pixman_region32_fini(&region->region);
644 free(region);
645}
646
647static void
648region_destroy(struct wl_client *client, struct wl_resource *resource)
649{
650 wl_resource_destroy(resource);
651}
652
653static void
654region_add(struct wl_client *client, struct wl_resource *resource,
655 int32_t x, int32_t y, int32_t width, int32_t height)
656{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400657 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400658
659 pixman_region32_union_rect(&region->region, &region->region,
660 x, y, width, height);
661}
662
663static void
664region_subtract(struct wl_client *client, struct wl_resource *resource,
665 int32_t x, int32_t y, int32_t width, int32_t height)
666{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400667 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400668 pixman_region32_t rect;
669
670 pixman_region32_init_rect(&rect, x, y, width, height);
671 pixman_region32_subtract(&region->region, &region->region, &rect);
672 pixman_region32_fini(&rect);
673}
674
675static const struct wl_region_interface region_interface = {
676 region_destroy,
677 region_add,
678 region_subtract
679};
680
681static void
682compositor_create_region(struct wl_client *client,
683 struct wl_resource *resource, uint32_t id)
684{
685 struct nested_region *region;
686
687 region = malloc(sizeof *region);
688 if (region == NULL) {
689 wl_resource_post_no_memory(resource);
690 return;
691 }
692
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400693 pixman_region32_init(&region->region);
694
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400695 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400696 wl_resource_create(client, &wl_region_interface, 1, id);
697 wl_resource_set_implementation(region->resource, &region_interface,
698 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400699}
700
701static const struct wl_compositor_interface compositor_interface = {
702 compositor_create_surface,
703 compositor_create_region
704};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400705
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400706static void
707compositor_bind(struct wl_client *client,
708 void *data, uint32_t version, uint32_t id)
709{
710 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400711 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400712
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400713 resource = wl_resource_create(client, &wl_compositor_interface,
714 MIN(version, 3), id);
715 wl_resource_set_implementation(resource, &compositor_interface,
716 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400717}
718
719static int
720nested_init_compositor(struct nested *nested)
721{
722 const char *extensions;
723 struct wl_event_loop *loop;
724 int fd, ret;
725
726 wl_list_init(&nested->surface_list);
727 wl_list_init(&nested->frame_callback_list);
728 nested->child_display = wl_display_create();
729 loop = wl_display_get_event_loop(nested->child_display);
730 fd = wl_event_loop_get_fd(loop);
731 nested->child_task.run = handle_child_data;
732 display_watch_fd(nested->display, fd,
733 EPOLLIN, &nested->child_task);
734
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400735 if (!wl_global_create(nested->child_display,
736 &wl_compositor_interface, 1,
737 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400738 return -1;
739
740 wl_display_init_shm(nested->child_display);
741
742 nested->egl_display = display_get_egl_display(nested->display);
743 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
744 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
745 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
746 return -1;
747 }
748
749 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
750 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
751 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
752 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
753 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
754 image_target_texture_2d =
755 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
756
757 ret = bind_display(nested->egl_display, nested->child_display);
758 if (!ret) {
759 fprintf(stderr, "failed to bind wl_display\n");
760 return -1;
761 }
762
763 return 0;
764}
765
766static struct nested *
767nested_create(struct display *display)
768{
769 struct nested *nested;
770
Peter Huttererf3d62272013-08-08 11:57:05 +1000771 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400772 if (nested == NULL)
773 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400774
775 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500776 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400777 window_set_title(nested->window, "Wayland Nested");
778 nested->display = display;
779
780 window_set_user_data(nested->window, nested);
781 widget_set_redraw_handler(nested->widget, redraw_handler);
782 window_set_keyboard_focus_handler(nested->window,
783 keyboard_focus_handler);
784
785 nested_init_compositor(nested);
786
787 widget_schedule_resize(nested->widget, 400, 400);
788
789 return nested;
790}
791
792static void
793nested_destroy(struct nested *nested)
794{
795 widget_destroy(nested->widget);
796 window_destroy(nested->window);
797 free(nested);
798}
799
800int
801main(int argc, char *argv[])
802{
803 struct display *display;
804 struct nested *nested;
805
806 display = display_create(&argc, argv);
807 if (display == NULL) {
808 fprintf(stderr, "failed to create display: %m\n");
809 return -1;
810 }
811
812 nested = nested_create(display);
813
Kristian Høgsbergcb61dcf2013-08-07 09:50:12 -0700814 launch_client(nested, "weston-nested-client");
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400815
816 display_run(display);
817
818 nested_destroy(nested);
819 display_destroy(display);
820
821 return 0;
822}