You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							632 lines
						
					
					
						
							16 KiB
						
					
					
				
			
		
		
	
	
							632 lines
						
					
					
						
							16 KiB
						
					
					
				| /*
 | |
|  * Copyright © 2013 Intel Corporation
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that copyright
 | |
|  * notice and this permission notice appear in supporting documentation, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #include <stdint.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <cairo.h>
 | |
| #include <math.h>
 | |
| #include <assert.h>
 | |
| #include <pixman.h>
 | |
| #include <sys/epoll.h>
 | |
| #include <sys/socket.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <EGL/egl.h>
 | |
| #include <EGL/eglext.h>
 | |
| #include <GLES2/gl2.h>
 | |
| #include <GLES2/gl2ext.h>
 | |
| 
 | |
| #include <cairo-gl.h>
 | |
| 
 | |
| #include <wayland-client.h>
 | |
| #define WL_HIDE_DEPRECATED
 | |
| #include <wayland-server.h>
 | |
| 
 | |
| #include "window.h"
 | |
| 
 | |
| #define MIN(x,y) (((x) < (y)) ? (x) : (y))
 | |
| 
 | |
| struct nested {
 | |
| 	struct display *display;
 | |
| 	struct window *window;
 | |
| 	struct widget *widget;
 | |
| 	struct wl_display *child_display;
 | |
| 	struct task child_task;
 | |
| 
 | |
| 	EGLDisplay egl_display;
 | |
| 	struct program *texture_program;
 | |
| 
 | |
| 	struct wl_list surface_list;
 | |
| 	struct wl_list frame_callback_list;
 | |
| };
 | |
| 
 | |
| struct nested_region {
 | |
| 	struct wl_resource *resource;
 | |
| 	pixman_region32_t region;
 | |
| };
 | |
| 
 | |
| struct nested_surface {
 | |
| 	struct wl_resource *resource;
 | |
| 	struct wl_resource *buffer_resource;
 | |
| 	struct nested *nested;
 | |
| 	EGLImageKHR *image;
 | |
| 	GLuint texture;
 | |
| 	struct wl_list link;
 | |
| 	cairo_surface_t *cairo_surface;
 | |
| };
 | |
| 
 | |
| struct nested_frame_callback {
 | |
| 	struct wl_resource *resource;
 | |
| 	struct wl_list link;
 | |
| };
 | |
| 
 | |
| static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
 | |
| static PFNEGLCREATEIMAGEKHRPROC create_image;
 | |
| static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
 | |
| static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
 | |
| static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
 | |
| static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
 | |
| 
 | |
| static void
 | |
| frame_callback(void *data, struct wl_callback *callback, uint32_t time)
 | |
| {
 | |
| 	struct nested *nested = data;
 | |
| 	struct nested_frame_callback *nc, *next;
 | |
| 
 | |
| 	if (callback)
 | |
| 		wl_callback_destroy(callback);
 | |
| 
 | |
| 	wl_list_for_each_safe(nc, next, &nested->frame_callback_list, link) {
 | |
| 		wl_callback_send_done(nc->resource, time);
 | |
| 		wl_resource_destroy(nc->resource);
 | |
| 	}
 | |
| 	wl_list_init(&nested->frame_callback_list);
 | |
| 
 | |
| 	/* FIXME: toytoolkit need a pre-block handler where we can
 | |
| 	 * call this. */
 | |
| 	wl_display_flush_clients(nested->child_display);
 | |
| }
 | |
| 
 | |
| static const struct wl_callback_listener frame_listener = {
 | |
| 	frame_callback
 | |
| };
 | |
| 
 | |
| static void
 | |
| redraw_handler(struct widget *widget, void *data)
 | |
| {
 | |
| 	struct nested *nested = data;
 | |
| 	cairo_surface_t *surface;
 | |
| 	cairo_t *cr;
 | |
| 	struct rectangle allocation;
 | |
| 	struct wl_callback *callback;
 | |
| 	struct nested_surface *s;
 | |
| 
 | |
| 	widget_get_allocation(nested->widget, &allocation);
 | |
| 
 | |
| 	surface = window_get_surface(nested->window);
 | |
| 
 | |
| 	cr = cairo_create(surface);
 | |
| 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
 | |
| 	cairo_rectangle(cr,
 | |
| 			allocation.x,
 | |
| 			allocation.y,
 | |
| 			allocation.width,
 | |
| 			allocation.height);
 | |
| 	cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
 | |
| 	cairo_fill(cr);
 | |
| 
 | |
| 	wl_list_for_each(s, &nested->surface_list, link) {
 | |
| 		display_acquire_window_surface(nested->display,
 | |
| 					       nested->window, NULL);
 | |
| 
 | |
| 		glBindTexture(GL_TEXTURE_2D, s->texture);
 | |
| 		image_target_texture_2d(GL_TEXTURE_2D, s->image);
 | |
| 
 | |
| 		display_release_window_surface(nested->display,
 | |
| 					       nested->window);
 | |
| 
 | |
| 		cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
 | |
| 		cairo_set_source_surface(cr, s->cairo_surface,
 | |
| 					 allocation.x + 10,
 | |
| 					 allocation.y + 10);
 | |
| 		cairo_rectangle(cr, allocation.x + 10,
 | |
| 				allocation.y + 10,
 | |
| 				allocation.width - 10,
 | |
| 				allocation.height - 10);
 | |
| 
 | |
| 		cairo_fill(cr);
 | |
| 	}
 | |
| 
 | |
| 	cairo_destroy(cr);
 | |
| 
 | |
| 	cairo_surface_destroy(surface);
 | |
| 
 | |
| 	callback = wl_surface_frame(window_get_wl_surface(nested->window));
 | |
| 	wl_callback_add_listener(callback, &frame_listener, nested);
 | |
| }
 | |
| 
 | |
| static void
 | |
| keyboard_focus_handler(struct window *window,
 | |
| 		       struct input *device, void *data)
 | |
| {
 | |
| 	struct nested *nested = data;
 | |
| 
 | |
| 	window_schedule_redraw(nested->window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| handle_child_data(struct task *task, uint32_t events)
 | |
| {
 | |
| 	struct nested *nested = container_of(task, struct nested, child_task);
 | |
| 	struct wl_event_loop *loop;
 | |
| 
 | |
| 	loop = wl_display_get_event_loop(nested->child_display);
 | |
| 
 | |
| 	wl_event_loop_dispatch(loop, -1);
 | |
| 	wl_display_flush_clients(nested->child_display);
 | |
| }
 | |
| 
 | |
| struct nested_client {
 | |
| 	struct wl_client *client;
 | |
| 	pid_t pid;
 | |
| };
 | |
| 
 | |
| static struct nested_client *
 | |
| launch_client(struct nested *nested, const char *path)
 | |
| {
 | |
| 	int sv[2];
 | |
| 	pid_t pid;
 | |
| 	struct nested_client *client;
 | |
| 
 | |
| 	client = malloc(sizeof *client);
 | |
| 	if (client == NULL)
 | |
| 		return NULL;
 | |
| 
 | |
| 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
 | |
| 		fprintf(stderr, "launch_client: "
 | |
| 			"socketpair failed while launching '%s': %m\n",
 | |
| 			path);
 | |
| 		free(client);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	pid = fork();
 | |
| 	if (pid == -1) {
 | |
| 		close(sv[0]);
 | |
| 		close(sv[1]);
 | |
| 		free(client);
 | |
| 		fprintf(stderr, "launch_client: "
 | |
| 			"fork failed while launching '%s': %m\n", path);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	if (pid == 0) {
 | |
| 		int clientfd;
 | |
| 		char s[32];
 | |
| 
 | |
| 		/* SOCK_CLOEXEC closes both ends, so we dup the fd to
 | |
| 		 * get a non-CLOEXEC fd to pass through exec. */
 | |
| 		clientfd = dup(sv[1]);
 | |
| 		if (clientfd == -1) {
 | |
| 			fprintf(stderr, "compositor: dup failed: %m\n");
 | |
| 			exit(-1);
 | |
| 		}
 | |
| 
 | |
| 		snprintf(s, sizeof s, "%d", clientfd);
 | |
| 		setenv("WAYLAND_SOCKET", s, 1);
 | |
| 
 | |
| 		execl(path, path, NULL);
 | |
| 
 | |
| 		fprintf(stderr, "compositor: executing '%s' failed: %m\n",
 | |
| 			path);
 | |
| 		exit(-1);
 | |
| 	}
 | |
| 
 | |
| 	close(sv[1]);
 | |
| 
 | |
| 	client->client = wl_client_create(nested->child_display, sv[0]);
 | |
| 	if (!client->client) {
 | |
| 		close(sv[0]);
 | |
| 		free(client);
 | |
| 		fprintf(stderr, "launch_client: "
 | |
| 			"wl_client_create failed while launching '%s'.\n",
 | |
| 			path);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	client->pid = pid;
 | |
| 
 | |
| 	return client;
 | |
| }
 | |
| 
 | |
| static void
 | |
| destroy_surface(struct wl_resource *resource)
 | |
| {
 | |
| 	struct nested_surface *surface = wl_resource_get_user_data(resource);
 | |
| 
 | |
| 	free(surface);
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_destroy(struct wl_client *client, struct wl_resource *resource)
 | |
| {
 | |
| 	wl_resource_destroy(resource);
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_attach(struct wl_client *client,
 | |
| 	       struct wl_resource *resource,
 | |
| 	       struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
 | |
| {
 | |
| 	struct nested_surface *surface = wl_resource_get_user_data(resource);
 | |
| 	struct nested *nested = surface->nested;
 | |
| 	EGLint format, width, height;
 | |
| 	cairo_device_t *device;
 | |
| 
 | |
| 	if (surface->buffer_resource)
 | |
| 		wl_buffer_send_release(surface->buffer_resource);
 | |
| 
 | |
| 	surface->buffer_resource = buffer_resource;
 | |
| 	if (!query_buffer(nested->egl_display, (void *) buffer_resource,
 | |
| 			  EGL_TEXTURE_FORMAT, &format)) {
 | |
| 		fprintf(stderr, "attaching non-egl wl_buffer\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (surface->image != EGL_NO_IMAGE_KHR)
 | |
| 		destroy_image(nested->egl_display, surface->image);
 | |
| 	if (surface->cairo_surface)
 | |
| 		cairo_surface_destroy(surface->cairo_surface);
 | |
| 
 | |
| 	switch (format) {
 | |
| 	case EGL_TEXTURE_RGB:
 | |
| 	case EGL_TEXTURE_RGBA:
 | |
| 		break;
 | |
| 	default:
 | |
| 		fprintf(stderr, "unhandled format: %x\n", format);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	surface->image = create_image(nested->egl_display, NULL,
 | |
| 				      EGL_WAYLAND_BUFFER_WL, buffer_resource,
 | |
| 				      NULL);
 | |
| 	if (surface->image == EGL_NO_IMAGE_KHR) {
 | |
| 		fprintf(stderr, "failed to create img\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	query_buffer(nested->egl_display,
 | |
| 		     (void *) buffer_resource, EGL_WIDTH, &width);
 | |
| 	query_buffer(nested->egl_display,
 | |
| 		     (void *) buffer_resource, EGL_HEIGHT, &height);
 | |
| 
 | |
| 	device = display_get_cairo_device(nested->display);
 | |
| 	surface->cairo_surface = 
 | |
| 		cairo_gl_surface_create_for_texture(device,
 | |
| 						    CAIRO_CONTENT_COLOR_ALPHA,
 | |
| 						    surface->texture,
 | |
| 						    width, height);
 | |
| 
 | |
| 	window_schedule_redraw(nested->window);
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_damage(struct wl_client *client,
 | |
| 	       struct wl_resource *resource,
 | |
| 	       int32_t x, int32_t y, int32_t width, int32_t height)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| destroy_frame_callback(struct wl_resource *resource)
 | |
| {
 | |
| 	struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
 | |
| 
 | |
| 	wl_list_remove(&callback->link);
 | |
| 	free(callback);
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_frame(struct wl_client *client,
 | |
| 	      struct wl_resource *resource, uint32_t id)
 | |
| {
 | |
| 	struct nested_frame_callback *callback;
 | |
| 	struct nested_surface *surface = wl_resource_get_user_data(resource);
 | |
| 	struct nested *nested = surface->nested;
 | |
| 
 | |
| 	callback = malloc(sizeof *callback);
 | |
| 	if (callback == NULL) {
 | |
| 		wl_resource_post_no_memory(resource);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	callback->resource = wl_resource_create(client,
 | |
| 						&wl_callback_interface, 1, id);
 | |
| 	wl_resource_set_implementation(callback->resource, NULL, callback,
 | |
| 				       destroy_frame_callback);
 | |
| 
 | |
| 	wl_list_insert(nested->frame_callback_list.prev, &callback->link);
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_set_opaque_region(struct wl_client *client,
 | |
| 			  struct wl_resource *resource,
 | |
| 			  struct wl_resource *region_resource)
 | |
| {
 | |
| 	fprintf(stderr, "surface_set_opaque_region\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_set_input_region(struct wl_client *client,
 | |
| 			 struct wl_resource *resource,
 | |
| 			 struct wl_resource *region_resource)
 | |
| {
 | |
| 	fprintf(stderr, "surface_set_input_region\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_commit(struct wl_client *client, struct wl_resource *resource)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| surface_set_buffer_transform(struct wl_client *client,
 | |
| 			     struct wl_resource *resource, int transform)
 | |
| {
 | |
| 	fprintf(stderr, "surface_set_buffer_transform\n");
 | |
| }
 | |
| 
 | |
| static const struct wl_surface_interface surface_interface = {
 | |
| 	surface_destroy,
 | |
| 	surface_attach,
 | |
| 	surface_damage,
 | |
| 	surface_frame,
 | |
| 	surface_set_opaque_region,
 | |
| 	surface_set_input_region,
 | |
| 	surface_commit,
 | |
| 	surface_set_buffer_transform
 | |
| };
 | |
| 
 | |
| static void
 | |
| compositor_create_surface(struct wl_client *client,
 | |
| 			  struct wl_resource *resource, uint32_t id)
 | |
| {
 | |
| 	struct nested *nested = wl_resource_get_user_data(resource);
 | |
| 	struct nested_surface *surface;
 | |
| 	
 | |
| 	surface = zalloc(sizeof *surface);
 | |
| 	if (surface == NULL) {
 | |
| 		wl_resource_post_no_memory(resource);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	surface->nested = nested;
 | |
| 
 | |
| 	display_acquire_window_surface(nested->display,
 | |
| 				       nested->window, NULL);
 | |
| 
 | |
| 	glGenTextures(1, &surface->texture);
 | |
| 	glBindTexture(GL_TEXTURE_2D, surface->texture);
 | |
| 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | |
| 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | |
| 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | |
| 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | |
| 
 | |
| 	display_release_window_surface(nested->display, nested->window);
 | |
| 
 | |
| 	surface->resource =
 | |
| 		wl_resource_create(client, &wl_surface_interface, 1, id);
 | |
| 
 | |
| 	wl_resource_set_implementation(surface->resource,
 | |
| 				       &surface_interface, surface,
 | |
| 				       destroy_surface);
 | |
| 
 | |
| 	wl_list_insert(nested->surface_list.prev, &surface->link);
 | |
| }
 | |
| 
 | |
| static void
 | |
| destroy_region(struct wl_resource *resource)
 | |
| {
 | |
| 	struct nested_region *region = wl_resource_get_user_data(resource);
 | |
| 
 | |
| 	pixman_region32_fini(®ion->region);
 | |
| 	free(region);
 | |
| }
 | |
| 
 | |
| static void
 | |
| region_destroy(struct wl_client *client, struct wl_resource *resource)
 | |
| {
 | |
| 	wl_resource_destroy(resource);
 | |
| }
 | |
| 
 | |
| static void
 | |
| region_add(struct wl_client *client, struct wl_resource *resource,
 | |
| 	   int32_t x, int32_t y, int32_t width, int32_t height)
 | |
| {
 | |
| 	struct nested_region *region = wl_resource_get_user_data(resource);
 | |
| 
 | |
| 	pixman_region32_union_rect(®ion->region, ®ion->region,
 | |
| 				   x, y, width, height);
 | |
| }
 | |
| 
 | |
| static void
 | |
| region_subtract(struct wl_client *client, struct wl_resource *resource,
 | |
| 		int32_t x, int32_t y, int32_t width, int32_t height)
 | |
| {
 | |
| 	struct nested_region *region = wl_resource_get_user_data(resource);
 | |
| 	pixman_region32_t rect;
 | |
| 
 | |
| 	pixman_region32_init_rect(&rect, x, y, width, height);
 | |
| 	pixman_region32_subtract(®ion->region, ®ion->region, &rect);
 | |
| 	pixman_region32_fini(&rect);
 | |
| }
 | |
| 
 | |
| static const struct wl_region_interface region_interface = {
 | |
| 	region_destroy,
 | |
| 	region_add,
 | |
| 	region_subtract
 | |
| };
 | |
| 
 | |
| static void
 | |
| compositor_create_region(struct wl_client *client,
 | |
| 			 struct wl_resource *resource, uint32_t id)
 | |
| {
 | |
| 	struct nested_region *region;
 | |
| 
 | |
| 	region = malloc(sizeof *region);
 | |
| 	if (region == NULL) {
 | |
| 		wl_resource_post_no_memory(resource);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	pixman_region32_init(®ion->region);
 | |
| 
 | |
| 	region->resource =
 | |
| 		wl_resource_create(client, &wl_region_interface, 1, id);
 | |
| 	wl_resource_set_implementation(region->resource, ®ion_interface,
 | |
| 				       region, destroy_region);
 | |
| }
 | |
| 
 | |
| static const struct wl_compositor_interface compositor_interface = {
 | |
| 	compositor_create_surface,
 | |
| 	compositor_create_region
 | |
| };
 | |
| 
 | |
| static void
 | |
| compositor_bind(struct wl_client *client,
 | |
| 		void *data, uint32_t version, uint32_t id)
 | |
| {
 | |
| 	struct nested *nested = data;
 | |
| 	struct wl_resource *resource;
 | |
| 
 | |
| 	resource = wl_resource_create(client, &wl_compositor_interface,
 | |
| 				      MIN(version, 3), id);
 | |
| 	wl_resource_set_implementation(resource, &compositor_interface,
 | |
| 				       nested, NULL);
 | |
| }
 | |
| 
 | |
| static int
 | |
| nested_init_compositor(struct nested *nested)
 | |
| {
 | |
| 	const char *extensions;
 | |
| 	struct wl_event_loop *loop;
 | |
| 	int fd, ret;
 | |
| 
 | |
| 	wl_list_init(&nested->surface_list);
 | |
| 	wl_list_init(&nested->frame_callback_list);
 | |
| 	nested->child_display = wl_display_create();
 | |
| 	loop = wl_display_get_event_loop(nested->child_display);
 | |
| 	fd = wl_event_loop_get_fd(loop);
 | |
| 	nested->child_task.run = handle_child_data;
 | |
| 	display_watch_fd(nested->display, fd,
 | |
| 			 EPOLLIN, &nested->child_task);
 | |
| 
 | |
| 	if (!wl_global_create(nested->child_display,
 | |
| 			      &wl_compositor_interface, 1,
 | |
| 			      nested, compositor_bind))
 | |
| 		return -1;
 | |
| 
 | |
| 	wl_display_init_shm(nested->child_display);
 | |
| 
 | |
| 	nested->egl_display = display_get_egl_display(nested->display);
 | |
| 	extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
 | |
| 	if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
 | |
| 		fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
 | |
| 	unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
 | |
| 	create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
 | |
| 	destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
 | |
| 	query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
 | |
| 	image_target_texture_2d =
 | |
| 		(void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
 | |
| 
 | |
| 	ret = bind_display(nested->egl_display, nested->child_display);
 | |
| 	if (!ret) {
 | |
| 		fprintf(stderr, "failed to bind wl_display\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct nested *
 | |
| nested_create(struct display *display)
 | |
| {
 | |
| 	struct nested *nested;
 | |
| 
 | |
| 	nested = zalloc(sizeof *nested);
 | |
| 	if (nested == NULL)
 | |
| 		return nested;
 | |
| 
 | |
| 	nested->window = window_create(display);
 | |
| 	nested->widget = window_frame_create(nested->window, nested);
 | |
| 	window_set_title(nested->window, "Wayland Nested");
 | |
| 	nested->display = display;
 | |
| 
 | |
| 	window_set_user_data(nested->window, nested);
 | |
| 	widget_set_redraw_handler(nested->widget, redraw_handler);
 | |
| 	window_set_keyboard_focus_handler(nested->window,
 | |
| 					  keyboard_focus_handler);
 | |
| 
 | |
| 	nested_init_compositor(nested);
 | |
| 
 | |
| 	widget_schedule_resize(nested->widget, 400, 400);
 | |
| 
 | |
| 	return nested;
 | |
| }
 | |
| 
 | |
| static void
 | |
| nested_destroy(struct nested *nested)
 | |
| {
 | |
| 	widget_destroy(nested->widget);
 | |
| 	window_destroy(nested->window);
 | |
| 	free(nested);
 | |
| }
 | |
| 
 | |
| int
 | |
| main(int argc, char *argv[])
 | |
| {
 | |
| 	struct display *display;
 | |
| 	struct nested *nested;
 | |
| 
 | |
| 	display = display_create(&argc, argv);
 | |
| 	if (display == NULL) {
 | |
| 		fprintf(stderr, "failed to create display: %m\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	nested = nested_create(display);
 | |
| 
 | |
| 	launch_client(nested, "weston-nested-client");
 | |
| 
 | |
| 	display_run(display);
 | |
| 
 | |
| 	nested_destroy(nested);
 | |
| 	display_destroy(display);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 |