blob: 6ac5248b125cf83e437fdb46da359d40eef379b3 [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;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040061};
62
63struct nested_region {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040064 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040065 pixman_region32_t region;
66};
67
Neil Roberts6bf23872013-09-08 18:49:15 +010068struct nested_buffer {
69 struct wl_resource *resource;
70 struct wl_signal destroy_signal;
71 struct wl_listener destroy_listener;
72 uint32_t busy_count;
73};
74
75struct nested_buffer_reference {
76 struct nested_buffer *buffer;
77 struct wl_listener destroy_listener;
78};
79
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040080struct nested_surface {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040081 struct wl_resource *resource;
Neil Roberts6bf23872013-09-08 18:49:15 +010082 struct nested_buffer_reference buffer_ref;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040083 struct nested *nested;
84 EGLImageKHR *image;
85 GLuint texture;
86 struct wl_list link;
87 cairo_surface_t *cairo_surface;
Neil Roberts15a8d342013-09-08 19:49:02 +010088
Neil Robertsf9b25412013-09-09 15:13:09 +010089 struct wl_list frame_callback_list;
90
Neil Roberts15a8d342013-09-08 19:49:02 +010091 struct {
92 /* wl_surface.attach */
93 int newly_attached;
94 struct nested_buffer *buffer;
95 struct wl_listener buffer_destroy_listener;
96
97 /* wl_surface.frame */
98 struct wl_list frame_callback_list;
Neil Roberts28557662013-09-08 20:24:14 +010099
100 /* wl_surface.damage */
101 pixman_region32_t damage;
Neil Roberts15a8d342013-09-08 19:49:02 +0100102 } pending;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400103};
104
105struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400106 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400107 struct wl_list link;
108};
109
110static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
111static PFNEGLCREATEIMAGEKHRPROC create_image;
112static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
113static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
114static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
115static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
116
117static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100118nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
119{
120 struct nested_buffer *buffer =
121 container_of(listener, struct nested_buffer, destroy_listener);
122
123 wl_signal_emit(&buffer->destroy_signal, buffer);
124 free(buffer);
125}
126
127static struct nested_buffer *
128nested_buffer_from_resource(struct wl_resource *resource)
129{
130 struct nested_buffer *buffer;
131 struct wl_listener *listener;
132
133 listener =
134 wl_resource_get_destroy_listener(resource,
135 nested_buffer_destroy_handler);
136
137 if (listener)
138 return container_of(listener, struct nested_buffer,
139 destroy_listener);
140
141 buffer = zalloc(sizeof *buffer);
142 if (buffer == NULL)
143 return NULL;
144
145 buffer->resource = resource;
146 wl_signal_init(&buffer->destroy_signal);
147 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
148 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
149
150 return buffer;
151}
152
153static void
154nested_buffer_reference_handle_destroy(struct wl_listener *listener,
155 void *data)
156{
157 struct nested_buffer_reference *ref =
158 container_of(listener, struct nested_buffer_reference,
159 destroy_listener);
160
161 assert((struct nested_buffer *)data == ref->buffer);
162 ref->buffer = NULL;
163}
164
165static void
166nested_buffer_reference(struct nested_buffer_reference *ref,
167 struct nested_buffer *buffer)
168{
169 if (buffer == ref->buffer)
170 return;
171
172 if (ref->buffer) {
173 ref->buffer->busy_count--;
174 if (ref->buffer->busy_count == 0) {
175 assert(wl_resource_get_client(ref->buffer->resource));
176 wl_resource_queue_event(ref->buffer->resource,
177 WL_BUFFER_RELEASE);
178 }
179 wl_list_remove(&ref->destroy_listener.link);
180 }
181
182 if (buffer) {
183 buffer->busy_count++;
184 wl_signal_add(&buffer->destroy_signal,
185 &ref->destroy_listener);
186
187 ref->destroy_listener.notify =
188 nested_buffer_reference_handle_destroy;
189 }
190
191 ref->buffer = buffer;
192}
193
194static void
Neil Robertsf9b25412013-09-09 15:13:09 +0100195flush_surface_frame_callback_list(struct nested_surface *surface,
196 uint32_t time)
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400197{
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400198 struct nested_frame_callback *nc, *next;
199
Neil Robertsf9b25412013-09-09 15:13:09 +0100200 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400201 wl_callback_send_done(nc->resource, time);
202 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400203 }
Neil Robertsf9b25412013-09-09 15:13:09 +0100204 wl_list_init(&surface->frame_callback_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400205
206 /* FIXME: toytoolkit need a pre-block handler where we can
207 * call this. */
Neil Robertsf9b25412013-09-09 15:13:09 +0100208 wl_display_flush_clients(surface->nested->child_display);
209}
210
211static void
212frame_callback(void *data, struct wl_callback *callback, uint32_t time)
213{
214 struct nested *nested = data;
215 struct nested_surface *surface;
216
217 wl_list_for_each(surface, &nested->surface_list, link)
218 flush_surface_frame_callback_list(surface, time);
219
220 if (callback)
221 wl_callback_destroy(callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400222}
223
224static const struct wl_callback_listener frame_listener = {
225 frame_callback
226};
227
228static void
229redraw_handler(struct widget *widget, void *data)
230{
231 struct nested *nested = data;
232 cairo_surface_t *surface;
233 cairo_t *cr;
234 struct rectangle allocation;
235 struct wl_callback *callback;
236 struct nested_surface *s;
237
238 widget_get_allocation(nested->widget, &allocation);
239
240 surface = window_get_surface(nested->window);
241
242 cr = cairo_create(surface);
243 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
244 cairo_rectangle(cr,
245 allocation.x,
246 allocation.y,
247 allocation.width,
248 allocation.height);
249 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
250 cairo_fill(cr);
251
252 wl_list_for_each(s, &nested->surface_list, link) {
Ander Conselvan de Oliveirad224bb92013-07-16 14:24:04 +0300253 display_acquire_window_surface(nested->display,
254 nested->window, NULL);
255
256 glBindTexture(GL_TEXTURE_2D, s->texture);
257 image_target_texture_2d(GL_TEXTURE_2D, s->image);
258
259 display_release_window_surface(nested->display,
260 nested->window);
261
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400262 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
263 cairo_set_source_surface(cr, s->cairo_surface,
264 allocation.x + 10,
265 allocation.y + 10);
266 cairo_rectangle(cr, allocation.x + 10,
267 allocation.y + 10,
268 allocation.width - 10,
269 allocation.height - 10);
270
271 cairo_fill(cr);
272 }
273
274 cairo_destroy(cr);
275
276 cairo_surface_destroy(surface);
277
278 callback = wl_surface_frame(window_get_wl_surface(nested->window));
279 wl_callback_add_listener(callback, &frame_listener, nested);
280}
281
282static void
283keyboard_focus_handler(struct window *window,
284 struct input *device, void *data)
285{
286 struct nested *nested = data;
287
288 window_schedule_redraw(nested->window);
289}
290
291static void
292handle_child_data(struct task *task, uint32_t events)
293{
294 struct nested *nested = container_of(task, struct nested, child_task);
295 struct wl_event_loop *loop;
296
297 loop = wl_display_get_event_loop(nested->child_display);
298
299 wl_event_loop_dispatch(loop, -1);
300 wl_display_flush_clients(nested->child_display);
301}
302
303struct nested_client {
304 struct wl_client *client;
305 pid_t pid;
306};
307
308static struct nested_client *
309launch_client(struct nested *nested, const char *path)
310{
311 int sv[2];
312 pid_t pid;
313 struct nested_client *client;
314
315 client = malloc(sizeof *client);
316 if (client == NULL)
317 return NULL;
318
319 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
320 fprintf(stderr, "launch_client: "
321 "socketpair failed while launching '%s': %m\n",
322 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700323 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400324 return NULL;
325 }
326
327 pid = fork();
328 if (pid == -1) {
329 close(sv[0]);
330 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700331 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400332 fprintf(stderr, "launch_client: "
333 "fork failed while launching '%s': %m\n", path);
334 return NULL;
335 }
336
337 if (pid == 0) {
338 int clientfd;
339 char s[32];
340
341 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
342 * get a non-CLOEXEC fd to pass through exec. */
343 clientfd = dup(sv[1]);
344 if (clientfd == -1) {
345 fprintf(stderr, "compositor: dup failed: %m\n");
346 exit(-1);
347 }
348
349 snprintf(s, sizeof s, "%d", clientfd);
350 setenv("WAYLAND_SOCKET", s, 1);
351
352 execl(path, path, NULL);
353
354 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
355 path);
356 exit(-1);
357 }
358
359 close(sv[1]);
360
361 client->client = wl_client_create(nested->child_display, sv[0]);
362 if (!client->client) {
363 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700364 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400365 fprintf(stderr, "launch_client: "
366 "wl_client_create failed while launching '%s'.\n",
367 path);
368 return NULL;
369 }
370
371 client->pid = pid;
372
373 return client;
374}
375
376static void
377destroy_surface(struct wl_resource *resource)
378{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400379 struct nested_surface *surface = wl_resource_get_user_data(resource);
Neil Roberts15a8d342013-09-08 19:49:02 +0100380 struct nested_frame_callback *cb, *next;
381
382 wl_list_for_each_safe(cb, next,
Neil Robertsf9b25412013-09-09 15:13:09 +0100383 &surface->frame_callback_list, link)
384 wl_resource_destroy(cb->resource);
385
386 wl_list_for_each_safe(cb, next,
Neil Roberts15a8d342013-09-08 19:49:02 +0100387 &surface->pending.frame_callback_list, link)
388 wl_resource_destroy(cb->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400389
Neil Roberts6bf23872013-09-08 18:49:15 +0100390 nested_buffer_reference(&surface->buffer_ref, NULL);
391
Neil Roberts28557662013-09-08 20:24:14 +0100392 pixman_region32_fini(&surface->pending.damage);
393
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000394 wl_list_remove(&surface->link);
395
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400396 free(surface);
397}
398
399static void
400surface_destroy(struct wl_client *client, struct wl_resource *resource)
401{
402 wl_resource_destroy(resource);
403}
404
405static void
406surface_attach(struct wl_client *client,
407 struct wl_resource *resource,
408 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
409{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400410 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400411 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100412 struct nested_buffer *buffer = NULL;
413
414 if (buffer_resource) {
415 int format;
416
417 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
418 EGL_TEXTURE_FORMAT, &format)) {
419 wl_resource_post_error(buffer_resource,
420 WL_DISPLAY_ERROR_INVALID_OBJECT,
421 "attaching non-egl wl_buffer");
422 return;
423 }
424
425 switch (format) {
426 case EGL_TEXTURE_RGB:
427 case EGL_TEXTURE_RGBA:
428 break;
429 default:
430 wl_resource_post_error(buffer_resource,
431 WL_DISPLAY_ERROR_INVALID_OBJECT,
432 "invalid format");
433 return;
434 }
435
436 buffer = nested_buffer_from_resource(buffer_resource);
437 if (buffer == NULL) {
438 wl_client_post_no_memory(client);
439 return;
440 }
441 }
442
443 if (surface->pending.buffer)
444 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
445
446 surface->pending.buffer = buffer;
447 surface->pending.newly_attached = 1;
448 if (buffer) {
449 wl_signal_add(&buffer->destroy_signal,
450 &surface->pending.buffer_destroy_listener);
451 }
452}
453
454static void
455nested_surface_attach(struct nested_surface *surface,
456 struct nested_buffer *buffer)
457{
458 struct nested *nested = surface->nested;
459 EGLint width, height;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400460 cairo_device_t *device;
461
Neil Roberts6bf23872013-09-08 18:49:15 +0100462 nested_buffer_reference(&surface->buffer_ref, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400463
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400464 if (surface->image != EGL_NO_IMAGE_KHR)
465 destroy_image(nested->egl_display, surface->image);
466 if (surface->cairo_surface)
467 cairo_surface_destroy(surface->cairo_surface);
468
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400469 surface->image = create_image(nested->egl_display, NULL,
Neil Roberts15a8d342013-09-08 19:49:02 +0100470 EGL_WAYLAND_BUFFER_WL, buffer->resource,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700471 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400472 if (surface->image == EGL_NO_IMAGE_KHR) {
473 fprintf(stderr, "failed to create img\n");
474 return;
475 }
476
Neil Roberts15a8d342013-09-08 19:49:02 +0100477 query_buffer(nested->egl_display, (void *) buffer->resource,
478 EGL_WIDTH, &width);
479 query_buffer(nested->egl_display, (void *) buffer->resource,
480 EGL_HEIGHT, &height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400481
482 device = display_get_cairo_device(nested->display);
483 surface->cairo_surface =
484 cairo_gl_surface_create_for_texture(device,
485 CAIRO_CONTENT_COLOR_ALPHA,
486 surface->texture,
487 width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400488}
489
490static void
491surface_damage(struct wl_client *client,
492 struct wl_resource *resource,
493 int32_t x, int32_t y, int32_t width, int32_t height)
494{
Neil Roberts28557662013-09-08 20:24:14 +0100495 struct nested_surface *surface = wl_resource_get_user_data(resource);
496
497 pixman_region32_union_rect(&surface->pending.damage,
498 &surface->pending.damage,
499 x, y, width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400500}
501
502static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400503destroy_frame_callback(struct wl_resource *resource)
504{
505 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
506
507 wl_list_remove(&callback->link);
508 free(callback);
509}
510
511static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400512surface_frame(struct wl_client *client,
513 struct wl_resource *resource, uint32_t id)
514{
515 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400516 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400517
518 callback = malloc(sizeof *callback);
519 if (callback == NULL) {
520 wl_resource_post_no_memory(resource);
521 return;
522 }
523
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400524 callback->resource = wl_resource_create(client,
525 &wl_callback_interface, 1, id);
526 wl_resource_set_implementation(callback->resource, NULL, callback,
527 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400528
Neil Roberts15a8d342013-09-08 19:49:02 +0100529 wl_list_insert(surface->pending.frame_callback_list.prev,
530 &callback->link);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400531}
532
533static void
534surface_set_opaque_region(struct wl_client *client,
535 struct wl_resource *resource,
536 struct wl_resource *region_resource)
537{
538 fprintf(stderr, "surface_set_opaque_region\n");
539}
540
541static void
542surface_set_input_region(struct wl_client *client,
543 struct wl_resource *resource,
544 struct wl_resource *region_resource)
545{
546 fprintf(stderr, "surface_set_input_region\n");
547}
548
549static void
Neil Roberts28557662013-09-08 20:24:14 +0100550empty_region(pixman_region32_t *region)
551{
552 pixman_region32_fini(region);
553 pixman_region32_init(region);
554}
555
556static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400557surface_commit(struct wl_client *client, struct wl_resource *resource)
558{
Neil Roberts15a8d342013-09-08 19:49:02 +0100559 struct nested_surface *surface = wl_resource_get_user_data(resource);
560 struct nested *nested = surface->nested;
561
562 /* wl_surface.attach */
563 if (surface->pending.newly_attached)
564 nested_surface_attach(surface, surface->pending.buffer);
565
566 if (surface->pending.buffer) {
567 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
568 surface->pending.buffer = NULL;
569 }
570 surface->pending.newly_attached = 0;
571
Neil Roberts28557662013-09-08 20:24:14 +0100572 /* wl_surface.damage */
573 empty_region(&surface->pending.damage);
574
Neil Roberts15a8d342013-09-08 19:49:02 +0100575 /* wl_surface.frame */
Neil Robertsf9b25412013-09-09 15:13:09 +0100576 wl_list_insert_list(&surface->frame_callback_list,
Neil Roberts15a8d342013-09-08 19:49:02 +0100577 &surface->pending.frame_callback_list);
578 wl_list_init(&surface->pending.frame_callback_list);
579
580 window_schedule_redraw(nested->window);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400581}
582
583static void
584surface_set_buffer_transform(struct wl_client *client,
585 struct wl_resource *resource, int transform)
586{
587 fprintf(stderr, "surface_set_buffer_transform\n");
588}
589
590static const struct wl_surface_interface surface_interface = {
591 surface_destroy,
592 surface_attach,
593 surface_damage,
594 surface_frame,
595 surface_set_opaque_region,
596 surface_set_input_region,
597 surface_commit,
598 surface_set_buffer_transform
599};
600
601static void
Neil Roberts15a8d342013-09-08 19:49:02 +0100602surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
603{
604 struct nested_surface *surface =
605 container_of(listener, struct nested_surface,
606 pending.buffer_destroy_listener);
607
608 surface->pending.buffer = NULL;
609}
610
611static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400612compositor_create_surface(struct wl_client *client,
613 struct wl_resource *resource, uint32_t id)
614{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400615 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400616 struct nested_surface *surface;
617
Peter Huttererf3d62272013-08-08 11:57:05 +1000618 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400619 if (surface == NULL) {
620 wl_resource_post_no_memory(resource);
621 return;
622 }
623
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400624 surface->nested = nested;
625
Neil Robertsf9b25412013-09-09 15:13:09 +0100626 wl_list_init(&surface->frame_callback_list);
627
Neil Roberts15a8d342013-09-08 19:49:02 +0100628 wl_list_init(&surface->pending.frame_callback_list);
629 surface->pending.buffer_destroy_listener.notify =
630 surface_handle_pending_buffer_destroy;
Neil Roberts28557662013-09-08 20:24:14 +0100631 pixman_region32_init(&surface->pending.damage);
Neil Roberts15a8d342013-09-08 19:49:02 +0100632
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400633 display_acquire_window_surface(nested->display,
634 nested->window, NULL);
635
636 glGenTextures(1, &surface->texture);
637 glBindTexture(GL_TEXTURE_2D, surface->texture);
638 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
639 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
640 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
641 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
642
643 display_release_window_surface(nested->display, nested->window);
644
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400645 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400646 wl_resource_create(client, &wl_surface_interface, 1, id);
647
648 wl_resource_set_implementation(surface->resource,
649 &surface_interface, surface,
650 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400651
652 wl_list_insert(nested->surface_list.prev, &surface->link);
653}
654
655static void
656destroy_region(struct wl_resource *resource)
657{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400658 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400659
660 pixman_region32_fini(&region->region);
661 free(region);
662}
663
664static void
665region_destroy(struct wl_client *client, struct wl_resource *resource)
666{
667 wl_resource_destroy(resource);
668}
669
670static void
671region_add(struct wl_client *client, struct wl_resource *resource,
672 int32_t x, int32_t y, int32_t width, int32_t height)
673{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400674 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400675
676 pixman_region32_union_rect(&region->region, &region->region,
677 x, y, width, height);
678}
679
680static void
681region_subtract(struct wl_client *client, struct wl_resource *resource,
682 int32_t x, int32_t y, int32_t width, int32_t height)
683{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400684 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400685 pixman_region32_t rect;
686
687 pixman_region32_init_rect(&rect, x, y, width, height);
688 pixman_region32_subtract(&region->region, &region->region, &rect);
689 pixman_region32_fini(&rect);
690}
691
692static const struct wl_region_interface region_interface = {
693 region_destroy,
694 region_add,
695 region_subtract
696};
697
698static void
699compositor_create_region(struct wl_client *client,
700 struct wl_resource *resource, uint32_t id)
701{
702 struct nested_region *region;
703
704 region = malloc(sizeof *region);
705 if (region == NULL) {
706 wl_resource_post_no_memory(resource);
707 return;
708 }
709
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400710 pixman_region32_init(&region->region);
711
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400712 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400713 wl_resource_create(client, &wl_region_interface, 1, id);
714 wl_resource_set_implementation(region->resource, &region_interface,
715 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400716}
717
718static const struct wl_compositor_interface compositor_interface = {
719 compositor_create_surface,
720 compositor_create_region
721};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400722
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400723static void
724compositor_bind(struct wl_client *client,
725 void *data, uint32_t version, uint32_t id)
726{
727 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400728 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400729
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400730 resource = wl_resource_create(client, &wl_compositor_interface,
731 MIN(version, 3), id);
732 wl_resource_set_implementation(resource, &compositor_interface,
733 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400734}
735
736static int
737nested_init_compositor(struct nested *nested)
738{
739 const char *extensions;
740 struct wl_event_loop *loop;
741 int fd, ret;
742
743 wl_list_init(&nested->surface_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400744 nested->child_display = wl_display_create();
745 loop = wl_display_get_event_loop(nested->child_display);
746 fd = wl_event_loop_get_fd(loop);
747 nested->child_task.run = handle_child_data;
748 display_watch_fd(nested->display, fd,
749 EPOLLIN, &nested->child_task);
750
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400751 if (!wl_global_create(nested->child_display,
752 &wl_compositor_interface, 1,
753 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400754 return -1;
755
756 wl_display_init_shm(nested->child_display);
757
758 nested->egl_display = display_get_egl_display(nested->display);
759 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
760 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
761 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
762 return -1;
763 }
764
765 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
766 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
767 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
768 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
769 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
770 image_target_texture_2d =
771 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
772
773 ret = bind_display(nested->egl_display, nested->child_display);
774 if (!ret) {
775 fprintf(stderr, "failed to bind wl_display\n");
776 return -1;
777 }
778
779 return 0;
780}
781
782static struct nested *
783nested_create(struct display *display)
784{
785 struct nested *nested;
786
Peter Huttererf3d62272013-08-08 11:57:05 +1000787 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400788 if (nested == NULL)
789 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400790
791 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500792 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400793 window_set_title(nested->window, "Wayland Nested");
794 nested->display = display;
795
796 window_set_user_data(nested->window, nested);
797 widget_set_redraw_handler(nested->widget, redraw_handler);
798 window_set_keyboard_focus_handler(nested->window,
799 keyboard_focus_handler);
800
801 nested_init_compositor(nested);
802
803 widget_schedule_resize(nested->widget, 400, 400);
804
805 return nested;
806}
807
808static void
809nested_destroy(struct nested *nested)
810{
811 widget_destroy(nested->widget);
812 window_destroy(nested->window);
813 free(nested);
814}
815
816int
817main(int argc, char *argv[])
818{
819 struct display *display;
820 struct nested *nested;
821
822 display = display_create(&argc, argv);
823 if (display == NULL) {
824 fprintf(stderr, "failed to create display: %m\n");
825 return -1;
826 }
827
828 nested = nested_create(display);
829
Kristian Høgsbergcb61dcf2013-08-07 09:50:12 -0700830 launch_client(nested, "weston-nested-client");
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400831
832 display_run(display);
833
834 nested_destroy(nested);
835 display_destroy(display);
836
837 return 0;
838}