mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	
		
			
	
	
		
			473 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			473 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2014 Red Hat, Inc.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * 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 <assert.h>
							 | 
						||
| 
								 | 
							
								#include <errno.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <unistd.h>
							 | 
						||
| 
								 | 
							
								#include <sys/time.h>
							 | 
						||
| 
								 | 
							
								#include <sys/socket.h>
							 | 
						||
| 
								 | 
							
								#include <sys/wait.h>
							 | 
						||
| 
								 | 
							
								#include <signal.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define WL_HIDE_DEPRECATED
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "test-compositor.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* --- Protocol --- */
							 | 
						||
| 
								 | 
							
								struct test_compositor;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const struct wl_message tc_requests[] = {
							 | 
						||
| 
								 | 
							
									/* this request serves as a barrier for synchronizing*/
							 | 
						||
| 
								 | 
							
									{ "stop_display", "u", NULL }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const struct wl_message tc_events[] = {
							 | 
						||
| 
								 | 
							
									{ "display_resumed", "", NULL }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const struct wl_interface test_compositor_interface = {
							 | 
						||
| 
								 | 
							
									"test", 1,
							 | 
						||
| 
								 | 
							
									1, tc_requests,
							 | 
						||
| 
								 | 
							
									1, tc_events
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct test_compositor_interface {
							 | 
						||
| 
								 | 
							
									void (*stop_display)(struct wl_client *client,
							 | 
						||
| 
								 | 
							
											     struct wl_resource *resource,
							 | 
						||
| 
								 | 
							
											     uint32_t num);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct test_compositor_listener {
							 | 
						||
| 
								 | 
							
									void (*display_resumed)(void *data, struct test_compositor *tc);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum {
							 | 
						||
| 
								 | 
							
									STOP_DISPLAY = 0
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum {
							 | 
						||
| 
								 | 
							
									DISPLAY_RESUMED = 0
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Since tests can run parallely, we need unique socket names
							 | 
						||
| 
								 | 
							
								 * for each test, otherwise the test can fail on wl_display_add_socket. */
							 | 
						||
| 
								 | 
							
								static const char *
							 | 
						||
| 
								 | 
							
								get_socket_name(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct timeval tv;
							 | 
						||
| 
								 | 
							
									static char retval[64];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									gettimeofday(&tv, NULL);
							 | 
						||
| 
								 | 
							
									snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld",
							 | 
						||
| 
								 | 
							
										 getpid(), tv.tv_sec, tv.tv_usec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return retval;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Check client's state and terminate display when all clients exited
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								client_destroyed(struct wl_listener *listener, void *data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct display *d;
							 | 
						||
| 
								 | 
							
									struct client_info *ci;
							 | 
						||
| 
								 | 
							
									siginfo_t status;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ci = wl_container_of(listener, ci, destroy_listener);
							 | 
						||
| 
								 | 
							
									d = ci->display;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									assert(waitid(P_PID, ci->pid, &status, WEXITED) != -1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch (status.si_code) {
							 | 
						||
| 
								 | 
							
									case CLD_KILLED:
							 | 
						||
| 
								 | 
							
									case CLD_DUMPED:
							 | 
						||
| 
								 | 
							
										fprintf(stderr, "Client '%s' was killed by signal %d\n",
							 | 
						||
| 
								 | 
							
											ci->name, status.si_status);
							 | 
						||
| 
								 | 
							
										ci->exit_code = status.si_status;
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									case CLD_EXITED:
							 | 
						||
| 
								 | 
							
										if (status.si_status != EXIT_SUCCESS)
							 | 
						||
| 
								 | 
							
											fprintf(stderr, "Client '%s' exited with code %d\n",
							 | 
						||
| 
								 | 
							
												ci->name, status.si_status);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										ci->exit_code = status.si_status;
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									++d->clients_terminated_no;
							 | 
						||
| 
								 | 
							
									if (d->clients_no == d->clients_terminated_no) {
							 | 
						||
| 
								 | 
							
										wl_display_terminate(d->wl_display);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* the clients are not removed from the list, because
							 | 
						||
| 
								 | 
							
									 * at the end of the test we check the exit codes of all
							 | 
						||
| 
								 | 
							
									 * clients. In the case that the test would go through
							 | 
						||
| 
								 | 
							
									 * the clients list manually, zero out the wl_client as a sign
							 | 
						||
| 
								 | 
							
									 * that the client is not running anymore */
							 | 
						||
| 
								 | 
							
									ci->wl_client = NULL;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								run_client(void (*client_main)(void), int wayland_sock, int client_pipe)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									char s[8];
							 | 
						||
| 
								 | 
							
									int can_continue = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Wait until display signals that client can continue */
							 | 
						||
| 
								 | 
							
									assert(read(client_pipe, &can_continue, sizeof(int)) == sizeof(int));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (can_continue == 0)
							 | 
						||
| 
								 | 
							
										abort(); /* error in parent */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* for wl_display_connect() */
							 | 
						||
| 
								 | 
							
									snprintf(s, sizeof s, "%d", wayland_sock);
							 | 
						||
| 
								 | 
							
									setenv("WAYLAND_SOCKET", s, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									client_main();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static struct client_info *
							 | 
						||
| 
								 | 
							
								display_create_client(struct display *d,
							 | 
						||
| 
								 | 
							
										      void (*client_main)(void),
							 | 
						||
| 
								 | 
							
										      const char *name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int pipe_cli[2];
							 | 
						||
| 
								 | 
							
									int sock_wayl[2];
							 | 
						||
| 
								 | 
							
									pid_t pid;
							 | 
						||
| 
								 | 
							
									int can_continue = 0;
							 | 
						||
| 
								 | 
							
									struct client_info *cl;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
							 | 
						||
| 
								 | 
							
									assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
							 | 
						||
| 
								 | 
							
									       && "Failed creating socket pair");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pid = fork();
							 | 
						||
| 
								 | 
							
									assert(pid != -1 && "Fork failed");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (pid == 0) {
							 | 
						||
| 
								 | 
							
										close(sock_wayl[1]);
							 | 
						||
| 
								 | 
							
										close(pipe_cli[1]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										run_client(client_main, sock_wayl[0], pipe_cli[0]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										close(sock_wayl[0]);
							 | 
						||
| 
								 | 
							
										close(pipe_cli[0]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										exit(0);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									close(sock_wayl[0]);
							 | 
						||
| 
								 | 
							
									close(pipe_cli[0]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									cl = calloc(1, sizeof(struct client_info));
							 | 
						||
| 
								 | 
							
									assert(cl && "Out of memory");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_list_insert(&d->clients, &cl->link);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									cl->display = d;
							 | 
						||
| 
								 | 
							
									cl->name = name;
							 | 
						||
| 
								 | 
							
									cl->pid = pid;
							 | 
						||
| 
								 | 
							
									cl->pipe = pipe_cli[1];
							 | 
						||
| 
								 | 
							
									cl->destroy_listener.notify = &client_destroyed;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
							 | 
						||
| 
								 | 
							
									if (!cl->wl_client) {
							 | 
						||
| 
								 | 
							
										int ret;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* abort the client */
							 | 
						||
| 
								 | 
							
										ret = write(cl->pipe, &can_continue, sizeof(int));
							 | 
						||
| 
								 | 
							
										assert(ret == sizeof(int) && "aborting the client failed");
							 | 
						||
| 
								 | 
							
										assert(0 && "Couldn't create wayland client");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_client_add_destroy_listener(cl->wl_client,
							 | 
						||
| 
								 | 
							
												       &cl->destroy_listener);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									++d->clients_no;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return cl;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct client_info *
							 | 
						||
| 
								 | 
							
								client_create_with_name(struct display *d, void (*client_main)(void),
							 | 
						||
| 
								 | 
							
											const char *name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int can_continue = 1;
							 | 
						||
| 
								 | 
							
									struct client_info *cl = display_create_client(d, client_main, name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* let the show begin! */
							 | 
						||
| 
								 | 
							
									assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return cl;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* wfr = waiting for resume */
							 | 
						||
| 
								 | 
							
								struct wfr {
							 | 
						||
| 
								 | 
							
									struct wl_resource *resource;
							 | 
						||
| 
								 | 
							
									struct wl_list link;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								handle_stop_display(struct wl_client *client,
							 | 
						||
| 
								 | 
							
										    struct wl_resource *resource, uint32_t num)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct display *d = wl_resource_get_user_data(resource);
							 | 
						||
| 
								 | 
							
									struct wfr *wfr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									assert(d->wfr_num < num
							 | 
						||
| 
								 | 
							
									       && "test error: Too many clients sent stop_display request");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									++d->wfr_num;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wfr = malloc(sizeof *wfr);
							 | 
						||
| 
								 | 
							
									if (!wfr) {
							 | 
						||
| 
								 | 
							
										wl_client_post_no_memory(client);
							 | 
						||
| 
								 | 
							
										assert(0 && "Out of memory");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wfr->resource = resource;
							 | 
						||
| 
								 | 
							
									wl_list_insert(&d->waiting_for_resume, &wfr->link);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (d->wfr_num == num)
							 | 
						||
| 
								 | 
							
										wl_display_terminate(d->wl_display);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const struct test_compositor_interface tc_implementation = {
							 | 
						||
| 
								 | 
							
									handle_stop_display
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								tc_bind(struct wl_client *client, void *data,
							 | 
						||
| 
								 | 
							
									uint32_t ver, uint32_t id)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct wl_resource *res;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									res = wl_resource_create(client, &test_compositor_interface, ver, id);
							 | 
						||
| 
								 | 
							
									if (!res) {
							 | 
						||
| 
								 | 
							
										wl_client_post_no_memory(client);
							 | 
						||
| 
								 | 
							
										assert(0 && "Out of memory");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_resource_set_implementation(res, &tc_implementation, data, NULL);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct display *
							 | 
						||
| 
								 | 
							
								display_create(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct display *d = NULL;
							 | 
						||
| 
								 | 
							
									struct wl_global *g;
							 | 
						||
| 
								 | 
							
									const char *socket_name;
							 | 
						||
| 
								 | 
							
									int stat = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									d = calloc(1, sizeof *d);
							 | 
						||
| 
								 | 
							
									assert(d && "Out of memory");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									d->wl_display = wl_display_create();
							 | 
						||
| 
								 | 
							
									assert(d->wl_display && "Creating display failed");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* hope the path won't be longer than 108 ... */
							 | 
						||
| 
								 | 
							
									socket_name = get_socket_name();
							 | 
						||
| 
								 | 
							
									stat = wl_display_add_socket(d->wl_display, socket_name);
							 | 
						||
| 
								 | 
							
									assert(stat == 0 && "Failed adding socket");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_list_init(&d->clients);
							 | 
						||
| 
								 | 
							
									d->clients_no = d->clients_terminated_no = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_list_init(&d->waiting_for_resume);
							 | 
						||
| 
								 | 
							
									d->wfr_num = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									g = wl_global_create(d->wl_display, &test_compositor_interface,
							 | 
						||
| 
								 | 
							
											     1, d, tc_bind);
							 | 
						||
| 
								 | 
							
									assert(g && "Creating test global failed");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return d;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								display_run(struct display *d)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									assert(d->wfr_num == 0
							 | 
						||
| 
								 | 
							
									       && "test error: Have waiting clients. Use display_resume.");
							 | 
						||
| 
								 | 
							
									wl_display_run(d->wl_display);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								display_resume(struct display *d)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct wfr *wfr, *next;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									assert(d->wfr_num > 0 && "test error: No clients waiting.");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_list_for_each_safe(wfr, next, &d->waiting_for_resume, link) {
							 | 
						||
| 
								 | 
							
										wl_resource_post_event(wfr->resource, DISPLAY_RESUMED);
							 | 
						||
| 
								 | 
							
										wl_list_remove(&wfr->link);
							 | 
						||
| 
								 | 
							
										free(wfr);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									assert(wl_list_empty(&d->waiting_for_resume));
							 | 
						||
| 
								 | 
							
									d->wfr_num = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_display_run(d->wl_display);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								display_destroy(struct display *d)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct client_info *cl, *next;
							 | 
						||
| 
								 | 
							
									int failed = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									assert(d->wfr_num == 0
							 | 
						||
| 
								 | 
							
									       && "test error: Didn't you forget to call display_resume?");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_list_for_each_safe(cl, next, &d->clients, link) {
							 | 
						||
| 
								 | 
							
										assert(cl->wl_client == NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (cl->exit_code != 0) {
							 | 
						||
| 
								 | 
							
											++failed;
							 | 
						||
| 
								 | 
							
											fprintf(stderr, "Client '%s' failed\n", cl->name);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										close(cl->pipe);
							 | 
						||
| 
								 | 
							
										free(cl);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_display_destroy(d->wl_display);
							 | 
						||
| 
								 | 
							
									free(d);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (failed) {
							 | 
						||
| 
								 | 
							
										fprintf(stderr, "%d child(ren) failed\n", failed);
							 | 
						||
| 
								 | 
							
										abort();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * --- Client helper functions ---
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								handle_display_resumed(void *data, struct test_compositor *tc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct client *c = data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c->display_stopped = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const struct test_compositor_listener tc_listener = {
							 | 
						||
| 
								 | 
							
									handle_display_resumed
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								registry_handle_globals(void *data, struct wl_registry *registry,
							 | 
						||
| 
								 | 
							
											uint32_t id, const char *intf, uint32_t ver)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct client *c = data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (strcmp(intf, "test") != 0)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
							 | 
						||
| 
								 | 
							
									assert(c->tc && "Failed binding to registry");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_proxy_add_listener((struct wl_proxy *) c->tc,
							 | 
						||
| 
								 | 
							
											      (void *) &tc_listener, c);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const struct wl_registry_listener registry_listener =
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									registry_handle_globals,
							 | 
						||
| 
								 | 
							
									NULL
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct client *client_connect()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct wl_registry *reg;
							 | 
						||
| 
								 | 
							
									struct client *c = calloc(1, sizeof *c);
							 | 
						||
| 
								 | 
							
									assert(c && "Out of memory");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c->wl_display = wl_display_connect(NULL);
							 | 
						||
| 
								 | 
							
									assert(c->wl_display && "Failed connecting to display");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* create test_compositor proxy. Do it with temporary
							 | 
						||
| 
								 | 
							
									 * registry so that client can define it's own listener later */
							 | 
						||
| 
								 | 
							
									reg = wl_display_get_registry(c->wl_display);
							 | 
						||
| 
								 | 
							
									assert(reg);
							 | 
						||
| 
								 | 
							
									wl_registry_add_listener(reg, ®istry_listener, c);
							 | 
						||
| 
								 | 
							
									wl_display_roundtrip(c->wl_display);
							 | 
						||
| 
								 | 
							
									assert(c->tc);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_registry_destroy(reg);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return c;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void
							 | 
						||
| 
								 | 
							
								check_error(struct wl_display *display)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									uint32_t ec, id;
							 | 
						||
| 
								 | 
							
									const struct wl_interface *intf;
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = wl_display_get_error(display);
							 | 
						||
| 
								 | 
							
									/* write out message about protocol error */
							 | 
						||
| 
								 | 
							
									if (err == EPROTO) {
							 | 
						||
| 
								 | 
							
										ec = wl_display_get_protocol_error(display, &intf, &id);
							 | 
						||
| 
								 | 
							
										fprintf(stderr, "Client: Got protocol error %u on interface %s"
							 | 
						||
| 
								 | 
							
												" (object %u)\n", ec, intf->name, id);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (err) {
							 | 
						||
| 
								 | 
							
										fprintf(stderr, "Client error: %s\n", strerror(err));
							 | 
						||
| 
								 | 
							
										abort();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void
							 | 
						||
| 
								 | 
							
								client_disconnect(struct client *c)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									/* check for errors */
							 | 
						||
| 
								 | 
							
									check_error(c->wl_display);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									wl_proxy_destroy((struct wl_proxy *) c->tc);
							 | 
						||
| 
								 | 
							
									wl_display_disconnect(c->wl_display);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* num is number of clients that requests to stop display.
							 | 
						||
| 
								 | 
							
								 * Display is stopped after it recieve num STOP_DISPLAY requests */
							 | 
						||
| 
								 | 
							
								int
							 | 
						||
| 
								 | 
							
								stop_display(struct client *c, int num)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int n = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c->display_stopped = 1;
							 | 
						||
| 
								 | 
							
									wl_proxy_marshal((struct wl_proxy *) c->tc, STOP_DISPLAY, num);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (c->display_stopped && n >= 0) {
							 | 
						||
| 
								 | 
							
										n = wl_display_dispatch(c->wl_display);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return n;
							 | 
						||
| 
								 | 
							
								}
							 |