Blame uwac/libuwac/uwac-display.c

Packit 1fb8d4
/*
Packit 1fb8d4
 * Copyright © 2014 David FORT <contact@hardening-consulting.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit 1fb8d4
 * documentation for any purpose is hereby granted without fee, provided that
Packit 1fb8d4
 * the above copyright notice appear in all copies and that both that copyright
Packit 1fb8d4
 * notice and this permission notice appear in supporting documentation, and
Packit 1fb8d4
 * that the name of the copyright holders not be used in advertising or
Packit 1fb8d4
 * publicity pertaining to distribution of the software without specific,
Packit 1fb8d4
 * written prior permission.  The copyright holders make no representations
Packit 1fb8d4
 * about the suitability of this software for any purpose.  It is provided "as
Packit 1fb8d4
 * is" without express or implied warranty.
Packit 1fb8d4
 *
Packit 1fb8d4
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Packit 1fb8d4
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Packit 1fb8d4
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Packit 1fb8d4
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
Packit 1fb8d4
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
Packit 1fb8d4
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
Packit 1fb8d4
 * OF THIS SOFTWARE.
Packit 1fb8d4
 */
Packit 1fb8d4
#include "uwac-priv.h"
Packit 1fb8d4
#include "uwac-utils.h"
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <stdarg.h>
Packit 1fb8d4
#include <assert.h>
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <time.h>
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
#include <sys/epoll.h>
Packit 1fb8d4
Packit 1fb8d4
#include "uwac-os.h"
Packit 1fb8d4
Packit 1fb8d4
#define TARGET_COMPOSITOR_INTERFACE 3
Packit 1fb8d4
#define TARGET_SHM_INTERFACE 1
Packit 1fb8d4
#define TARGET_SHELL_INTERFACE 1
Packit 1fb8d4
#define TARGET_DDM_INTERFACE 1
Packit 1fb8d4
#define TARGET_SEAT_INTERFACE 5
Packit 1fb8d4
#define TARGET_XDG_VERSION 5 /* The version of xdg-shell that we implement */
Packit 1fb8d4
Packit 1fb8d4
static const char* event_names[] =
Packit 1fb8d4
{
Packit 1fb8d4
	"new seat",
Packit 1fb8d4
	"removed seat",
Packit 1fb8d4
	"new output",
Packit 1fb8d4
	"configure",
Packit 1fb8d4
	"pointer enter",
Packit 1fb8d4
	"pointer leave",
Packit 1fb8d4
	"pointer motion",
Packit 1fb8d4
	"pointer buttons",
Packit 1fb8d4
	"pointer axis",
Packit 1fb8d4
	"keyboard enter",
Packit 1fb8d4
	"key",
Packit 1fb8d4
	"touch frame begin",
Packit 1fb8d4
	"touch up",
Packit 1fb8d4
	"touch down",
Packit 1fb8d4
	"touch motion",
Packit 1fb8d4
	"touch cancel",
Packit 1fb8d4
	"touch frame end",
Packit 1fb8d4
	"frame done",
Packit 1fb8d4
	"close",
Packit 1fb8d4
	NULL
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
bool uwac_default_error_handler(UwacDisplay* display, UwacReturnCode code, const char* msg, ...)
Packit 1fb8d4
{
Packit 1fb8d4
	va_list args;
Packit 1fb8d4
	va_start(args, msg);
Packit 1fb8d4
	vfprintf(stderr, "%s", args);
Packit 1fb8d4
	va_end(args);
Packit 1fb8d4
	return false;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UwacErrorHandler uwacErrorHandler = uwac_default_error_handler;
Packit 1fb8d4
Packit 1fb8d4
void UwacInstallErrorHandler(UwacErrorHandler handler)
Packit 1fb8d4
{
Packit 1fb8d4
	if (handler)
Packit 1fb8d4
		uwacErrorHandler = handler;
Packit 1fb8d4
	else
Packit 1fb8d4
		uwacErrorHandler = uwac_default_error_handler;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
static void cb_shm_format(void* data, struct wl_shm* wl_shm, uint32_t format)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacDisplay* d = data;
Packit 1fb8d4
Packit 1fb8d4
	if (format == WL_SHM_FORMAT_RGB565)
Packit 1fb8d4
		d->has_rgb565 = true;
Packit 1fb8d4
Packit 1fb8d4
	d->shm_formats_nb++;
Packit 1fb8d4
	d->shm_formats = xrealloc((void*)d->shm_formats, sizeof(enum wl_shm_format) * d->shm_formats_nb);
Packit 1fb8d4
	d->shm_formats[d->shm_formats_nb - 1] = format;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
struct wl_shm_listener shm_listener =
Packit 1fb8d4
{
Packit 1fb8d4
	cb_shm_format
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static void xdg_shell_ping(void* data, struct xdg_shell* shell, uint32_t serial)
Packit 1fb8d4
{
Packit 1fb8d4
	xdg_shell_pong(shell, serial);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static const struct xdg_shell_listener xdg_shell_listener =
Packit 1fb8d4
{
Packit 1fb8d4
	xdg_shell_ping,
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
#ifdef BUILD_FULLSCREEN_SHELL
Packit 1fb8d4
static void fullscreen_capability(void* data, struct _wl_fullscreen_shell* _wl_fullscreen_shell,
Packit 1fb8d4
                                  uint32_t capabilty)
Packit 1fb8d4
{
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static const struct _wl_fullscreen_shell_listener fullscreen_shell_listener =
Packit 1fb8d4
{
Packit 1fb8d4
	fullscreen_capability,
Packit 1fb8d4
};
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
static UwacSeat* display_destroy_seat(UwacDisplay* d, uint32_t name)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacSeat* seat;
Packit 1fb8d4
	wl_list_for_each(seat, &d->seats, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (seat->seat_id == name)
Packit 1fb8d4
		{
Packit 1fb8d4
			UwacSeatDestroy(seat);
Packit 1fb8d4
			return seat;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t id,
Packit 1fb8d4
                                   const char* interface, uint32_t version)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacDisplay* d = data;
Packit 1fb8d4
	UwacGlobal* global;
Packit 1fb8d4
	global = xmalloc(sizeof * global);
Packit 1fb8d4
	global->name = id;
Packit 1fb8d4
	global->interface = xstrdup(interface);
Packit 1fb8d4
	global->version = version;
Packit 1fb8d4
	wl_list_insert(d->globals.prev, &global->link);
Packit 1fb8d4
Packit 1fb8d4
	if (strcmp(interface, "wl_compositor") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface,
Packit 1fb8d4
		                                 min(TARGET_COMPOSITOR_INTERFACE, version));
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "wl_shm") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->shm = wl_registry_bind(registry, id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version));
Packit 1fb8d4
		wl_shm_add_listener(d->shm, &shm_listener, d);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "wl_output") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacOutput* output;
Packit 1fb8d4
		UwacOutputNewEvent* ev;
Packit 1fb8d4
		output = UwacCreateOutput(d, id, version);
Packit 1fb8d4
Packit 1fb8d4
		if (!output)
Packit 1fb8d4
		{
Packit 1fb8d4
			assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create output\n"));
Packit 1fb8d4
			return;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		ev = (UwacOutputNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_OUTPUT);
Packit 1fb8d4
Packit 1fb8d4
		if (ev)
Packit 1fb8d4
			ev->output = output;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "wl_seat") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacSeatNewEvent* ev;
Packit 1fb8d4
		UwacSeat* seat;
Packit 1fb8d4
		seat = UwacSeatNew(d, id, min(version, TARGET_SEAT_INTERFACE));
Packit 1fb8d4
Packit 1fb8d4
		if (!seat)
Packit 1fb8d4
		{
Packit 1fb8d4
			assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat\n"));
Packit 1fb8d4
			return;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		ev = (UwacSeatNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT);
Packit 1fb8d4
Packit 1fb8d4
		if (!ev)
Packit 1fb8d4
		{
Packit 1fb8d4
			assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat event\n"));
Packit 1fb8d4
			return;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		ev->seat = seat;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "wl_data_device_manager") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface,
Packit 1fb8d4
		                         min(TARGET_DDM_INTERFACE, version));
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "wl_shell") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->shell = wl_registry_bind(registry, id, &wl_shell_interface, min(TARGET_SHELL_INTERFACE,
Packit 1fb8d4
		                            version));
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "xdg_shell") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->xdg_shell = wl_registry_bind(registry, id, &xdg_shell_interface, 1);
Packit 1fb8d4
		xdg_shell_use_unstable_version(d->xdg_shell, TARGET_XDG_VERSION);
Packit 1fb8d4
		xdg_shell_add_listener(d->xdg_shell, &xdg_shell_listener, d);
Packit 1fb8d4
#if BUILD_IVI
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "ivi_application") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
Packit 1fb8d4
#endif
Packit 1fb8d4
#if BUILD_FULLSCREEN_SHELL
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "_wl_fullscreen_shell") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->fullscreen_shell = wl_registry_bind(registry, id, &_wl_fullscreen_shell_interface, 1);
Packit 1fb8d4
		_wl_fullscreen_shell_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d);
Packit 1fb8d4
#endif
Packit 1fb8d4
#if 0
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "text_cursor_position") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->text_cursor_position = wl_registry_bind(registry, id, &text_cursor_position_interface, 1);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "workspace_manager") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		//init_workspace_manager(d, id);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (strcmp(interface, "wl_subcompositor") == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
Packit 1fb8d4
#endif
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void registry_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacDisplay* d = data;
Packit 1fb8d4
	UwacGlobal* global;
Packit 1fb8d4
	UwacGlobal* tmp;
Packit 1fb8d4
	wl_list_for_each_safe(global, tmp, &d->globals, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (global->name != name)
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
#if 0
Packit 1fb8d4
Packit 1fb8d4
		if (strcmp(global->interface, "wl_output") == 0)
Packit 1fb8d4
			display_destroy_output(d, name);
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
		if (strcmp(global->interface, "wl_seat") == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			UwacSeatRemovedEvent* ev;
Packit 1fb8d4
			UwacSeat* seat;
Packit 1fb8d4
			seat = display_destroy_seat(d, name);
Packit 1fb8d4
			ev = (UwacSeatRemovedEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT);
Packit 1fb8d4
Packit 1fb8d4
			if (ev)
Packit 1fb8d4
				ev->id = name;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		wl_list_remove(&global->link);
Packit 1fb8d4
		free(global->interface);
Packit 1fb8d4
		free(global);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void UwacDestroyGlobal(UwacGlobal* global)
Packit 1fb8d4
{
Packit 1fb8d4
	free(global->interface);
Packit 1fb8d4
	wl_list_remove(&global->link);
Packit 1fb8d4
	free(global);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void* display_bind(UwacDisplay* display, uint32_t name, const struct wl_interface* interface,
Packit 1fb8d4
                   uint32_t version)
Packit 1fb8d4
{
Packit 1fb8d4
	return wl_registry_bind(display->registry, name, interface, version);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static const struct wl_registry_listener registry_listener =
Packit 1fb8d4
{
Packit 1fb8d4
	registry_handle_global,
Packit 1fb8d4
	registry_handle_global_remove
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task)
Packit 1fb8d4
{
Packit 1fb8d4
	struct epoll_event ep;
Packit 1fb8d4
	ep.events = events;
Packit 1fb8d4
	ep.data.ptr = task;
Packit 1fb8d4
	return epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void UwacDisplayUnwatchFd(UwacDisplay* display, int fd)
Packit 1fb8d4
{
Packit 1fb8d4
	epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void display_exit(UwacDisplay* display)
Packit 1fb8d4
{
Packit 1fb8d4
	display->running = false;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void display_dispatch_events(UwacTask* task, uint32_t events)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacDisplay* display = container_of(task, UwacDisplay, dispatch_fd_task);
Packit 1fb8d4
	struct epoll_event ep;
Packit 1fb8d4
	int ret;
Packit 1fb8d4
	display->display_fd_events = events;
Packit 1fb8d4
Packit 1fb8d4
	if ((events & EPOLLERR) || (events & EPOLLHUP))
Packit 1fb8d4
	{
Packit 1fb8d4
		display_exit(display);
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (events & EPOLLIN)
Packit 1fb8d4
	{
Packit 1fb8d4
		ret = wl_display_dispatch(display->display);
Packit 1fb8d4
Packit 1fb8d4
		if (ret == -1)
Packit 1fb8d4
		{
Packit 1fb8d4
			display_exit(display);
Packit 1fb8d4
			return;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (events & EPOLLOUT)
Packit 1fb8d4
	{
Packit 1fb8d4
		ret = wl_display_flush(display->display);
Packit 1fb8d4
Packit 1fb8d4
		if (ret == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
Packit 1fb8d4
			ep.data.ptr = &display->dispatch_fd_task;
Packit 1fb8d4
			epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep);
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (ret == -1 && errno != EAGAIN)
Packit 1fb8d4
		{
Packit 1fb8d4
			display_exit(display);
Packit 1fb8d4
			return;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
UwacDisplay* UwacOpenDisplay(const char* name, UwacReturnCode* err)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacDisplay* ret;
Packit 1fb8d4
	ret = (UwacDisplay*)calloc(1, sizeof(*ret));
Packit 1fb8d4
Packit 1fb8d4
	if (!ret)
Packit 1fb8d4
	{
Packit 1fb8d4
		*err = UWAC_ERROR_NOMEMORY;
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	wl_list_init(&ret->globals);
Packit 1fb8d4
	wl_list_init(&ret->seats);
Packit 1fb8d4
	wl_list_init(&ret->outputs);
Packit 1fb8d4
	wl_list_init(&ret->windows);
Packit 1fb8d4
	ret->display = wl_display_connect(name);
Packit 1fb8d4
Packit 1fb8d4
	if (ret->display == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		fprintf(stderr, "failed to connect to Wayland display %s: %m\n", name);
Packit 1fb8d4
		*err = UWAC_ERROR_UNABLE_TO_CONNECT;
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret->epoll_fd = uwac_os_epoll_create_cloexec();
Packit 1fb8d4
Packit 1fb8d4
	if (ret->epoll_fd < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		*err = UWAC_NOT_ENOUGH_RESOURCES;
Packit 1fb8d4
		goto out_disconnect;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret->display_fd = wl_display_get_fd(ret->display);
Packit 1fb8d4
	ret->registry = wl_display_get_registry(ret->display);
Packit 1fb8d4
Packit 1fb8d4
	if (!ret->registry)
Packit 1fb8d4
	{
Packit 1fb8d4
		*err = UWAC_ERROR_NOMEMORY;
Packit 1fb8d4
		goto out_close_epoll;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	wl_registry_add_listener(ret->registry, &registry_listener, ret);
Packit 1fb8d4
Packit 1fb8d4
	if ((wl_display_roundtrip(ret->display) < 0) || (wl_display_roundtrip(ret->display) < 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		uwacErrorHandler(ret, UWAC_ERROR_UNABLE_TO_CONNECT, "Failed to process Wayland connection: %m\n");
Packit 1fb8d4
		*err = UWAC_ERROR_UNABLE_TO_CONNECT;
Packit 1fb8d4
		goto out_free_registry;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret->dispatch_fd_task.run = display_dispatch_events;
Packit 1fb8d4
Packit 1fb8d4
	if (UwacDisplayWatchFd(ret, ret->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP,
Packit 1fb8d4
	                       &ret->dispatch_fd_task) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		uwacErrorHandler(ret, UWAC_ERROR_INTERNAL, "unable to watch display fd: %m\n");
Packit 1fb8d4
		*err = UWAC_ERROR_INTERNAL;
Packit 1fb8d4
		goto out_free_registry;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret->running = true;
Packit 1fb8d4
	ret->last_error = *err = UWAC_SUCCESS;
Packit 1fb8d4
	return ret;
Packit 1fb8d4
out_free_registry:
Packit 1fb8d4
	wl_registry_destroy(ret->registry);
Packit 1fb8d4
out_close_epoll:
Packit 1fb8d4
	close(ret->epoll_fd);
Packit 1fb8d4
out_disconnect:
Packit 1fb8d4
	wl_display_disconnect(ret->display);
Packit 1fb8d4
out_free:
Packit 1fb8d4
	free(ret);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int UwacDisplayDispatch(UwacDisplay* display, int timeout)
Packit 1fb8d4
{
Packit 1fb8d4
	int ret, count, i;
Packit 1fb8d4
	UwacTask* task;
Packit 1fb8d4
	struct epoll_event ep[16];
Packit 1fb8d4
	wl_display_dispatch_pending(display->display);
Packit 1fb8d4
Packit 1fb8d4
	if (!display->running)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	ret = wl_display_flush(display->display);
Packit 1fb8d4
Packit 1fb8d4
	if (ret < 0 && errno == EAGAIN)
Packit 1fb8d4
	{
Packit 1fb8d4
		ep[0].events = (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP);
Packit 1fb8d4
		ep[0].data.ptr = &display->dispatch_fd_task;
Packit 1fb8d4
		epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep[0]);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (ret < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	count = epoll_wait(display->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < count; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		task = ep[i].data.ptr;
Packit 1fb8d4
		task->run(task, ep[i].events);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
UwacReturnCode UwacDisplayGetLastError(const UwacDisplay* display)
Packit 1fb8d4
{
Packit 1fb8d4
	return display->last_error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacDisplay* display;
Packit 1fb8d4
	UwacSeat* seat, *tmpSeat;
Packit 1fb8d4
	UwacWindow* window, *tmpWindow;
Packit 1fb8d4
	UwacOutput* output, *tmpOutput;
Packit 1fb8d4
	UwacGlobal* global, *tmpGlobal;
Packit 1fb8d4
	assert(pdisplay);
Packit 1fb8d4
	display = *pdisplay;
Packit 1fb8d4
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
		return UWAC_ERROR_INVALID_DISPLAY;
Packit 1fb8d4
Packit 1fb8d4
	/* destroy windows */
Packit 1fb8d4
	wl_list_for_each_safe(window, tmpWindow, &display->windows, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacDestroyWindow(&window);
Packit 1fb8d4
	}
Packit 1fb8d4
	/* destroy seats */
Packit 1fb8d4
	wl_list_for_each_safe(seat, tmpSeat, &display->seats, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacSeatDestroy(seat);
Packit 1fb8d4
	}
Packit 1fb8d4
	/* destroy output */
Packit 1fb8d4
	wl_list_for_each_safe(output, tmpOutput, &display->outputs, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacDestroyOutput(output);
Packit 1fb8d4
	}
Packit 1fb8d4
	/* destroy globals */
Packit 1fb8d4
	wl_list_for_each_safe(global, tmpGlobal, &display->globals, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacDestroyGlobal(global);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (display->compositor)
Packit 1fb8d4
		wl_compositor_destroy(display->compositor);
Packit 1fb8d4
Packit 1fb8d4
#ifdef BUILD_FULLSCREEN_SHELL
Packit 1fb8d4
Packit 1fb8d4
	if (display->fullscreen_shell)
Packit 1fb8d4
		_wl_fullscreen_shell_destroy(display->fullscreen_shell);
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifdef BUILD_IVI
Packit 1fb8d4
Packit 1fb8d4
	if (display->ivi_application)
Packit 1fb8d4
		ivi_application_destroy(display->ivi_application);
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (display->xdg_shell)
Packit 1fb8d4
		xdg_shell_destroy(display->xdg_shell);
Packit 1fb8d4
Packit 1fb8d4
	if (display->shell)
Packit 1fb8d4
		wl_shell_destroy(display->shell);
Packit 1fb8d4
Packit 1fb8d4
	if (display->shm)
Packit 1fb8d4
		wl_shm_destroy(display->shm);
Packit 1fb8d4
Packit 1fb8d4
	if (display->subcompositor)
Packit 1fb8d4
		wl_subcompositor_destroy(display->subcompositor);
Packit 1fb8d4
Packit 1fb8d4
	if (display->data_device_manager)
Packit 1fb8d4
		wl_data_device_manager_destroy(display->data_device_manager);
Packit 1fb8d4
Packit 1fb8d4
	free(display->shm_formats);
Packit 1fb8d4
	wl_registry_destroy(display->registry);
Packit 1fb8d4
	close(display->epoll_fd);
Packit 1fb8d4
	wl_display_disconnect(display->display);
Packit 1fb8d4
Packit 1fb8d4
	/* cleanup the event queue */
Packit 1fb8d4
	while (display->push_queue)
Packit 1fb8d4
	{
Packit 1fb8d4
		UwacEventListItem* item = display->push_queue;
Packit 1fb8d4
		display->push_queue = item->tail;
Packit 1fb8d4
		free(item);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(display);
Packit 1fb8d4
	*pdisplay = NULL;
Packit 1fb8d4
	return UWAC_SUCCESS;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int UwacDisplayGetFd(UwacDisplay* display)
Packit 1fb8d4
{
Packit 1fb8d4
	return display->epoll_fd;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static const char* errorStrings[] =
Packit 1fb8d4
{
Packit 1fb8d4
	"success",
Packit 1fb8d4
	"out of memory error",
Packit 1fb8d4
	"unable to connect to wayland display",
Packit 1fb8d4
	"invalid UWAC display",
Packit 1fb8d4
	"not enough resources",
Packit 1fb8d4
	"timed out",
Packit 1fb8d4
	"not found",
Packit 1fb8d4
	"closed connection",
Packit 1fb8d4
Packit 1fb8d4
	"internal error",
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
const char* UwacErrorString(UwacReturnCode error)
Packit 1fb8d4
{
Packit 1fb8d4
	if (error < UWAC_SUCCESS || error >= UWAC_ERROR_LAST)
Packit 1fb8d4
		return "invalid error code";
Packit 1fb8d4
Packit 1fb8d4
	return errorStrings[error];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay* display, const char* name,
Packit 1fb8d4
        uint32_t* version)
Packit 1fb8d4
{
Packit 1fb8d4
	const UwacGlobal* global;
Packit 1fb8d4
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
		return UWAC_ERROR_INVALID_DISPLAY;
Packit 1fb8d4
Packit 1fb8d4
	wl_list_for_each(global, &display->globals, link)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(global->interface, name) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (version)
Packit 1fb8d4
				*version = global->version;
Packit 1fb8d4
Packit 1fb8d4
			return UWAC_SUCCESS;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	return UWAC_NOT_FOUND;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!display->shm)
Packit 1fb8d4
	{
Packit 1fb8d4
		display->last_error = UWAC_NOT_FOUND;
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	display->last_error = UWAC_SUCCESS;
Packit 1fb8d4
	return display->shm_formats_nb;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay* display, enum wl_shm_format* formats,
Packit 1fb8d4
        int formats_size, int* filled)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
		return UWAC_ERROR_INVALID_DISPLAY;
Packit 1fb8d4
Packit 1fb8d4
	*filled = min(display->shm_formats_nb, formats_size);
Packit 1fb8d4
	memcpy(formats, (const void*)display->shm_formats, *filled * sizeof(enum wl_shm_format));
Packit 1fb8d4
	return UWAC_SUCCESS;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
uint32_t UwacDisplayGetNbOutputs(UwacDisplay* display)
Packit 1fb8d4
{
Packit 1fb8d4
	return wl_list_length(&display->outputs);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UwacOutput* UwacDisplayGetOutput(UwacDisplay* display, int index)
Packit 1fb8d4
{
Packit 1fb8d4
	struct wl_list* l;
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0, l = &display->outputs; l && i < index; i++, l = l->next)
Packit 1fb8d4
		;
Packit 1fb8d4
Packit 1fb8d4
	if (!l)
Packit 1fb8d4
	{
Packit 1fb8d4
		display->last_error = UWAC_NOT_FOUND;
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	display->last_error = UWAC_SUCCESS;
Packit 1fb8d4
	return container_of(l, UwacOutput, link);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UwacReturnCode UwacOutputGetResolution(UwacOutput* output, UwacSize* resolution)
Packit 1fb8d4
{
Packit 1fb8d4
	*resolution = output->resolution;
Packit 1fb8d4
	return UWAC_SUCCESS;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
UwacEvent* UwacDisplayNewEvent(UwacDisplay* display, int type)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacEventListItem* ret;
Packit 1fb8d4
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
	{
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret = zalloc(sizeof(UwacEventListItem));
Packit 1fb8d4
Packit 1fb8d4
	if (!ret)
Packit 1fb8d4
	{
Packit 1fb8d4
		assert(uwacErrorHandler(display, UWAC_ERROR_NOMEMORY, "unable to allocate a '%s' event",
Packit 1fb8d4
		                        event_names[type]));
Packit 1fb8d4
		display->last_error = UWAC_ERROR_NOMEMORY;
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret->event.type = type;
Packit 1fb8d4
	ret->tail = display->push_queue;
Packit 1fb8d4
Packit 1fb8d4
	if (ret->tail)
Packit 1fb8d4
		ret->tail->head = ret;
Packit 1fb8d4
	else
Packit 1fb8d4
		display->pop_queue = ret;
Packit 1fb8d4
Packit 1fb8d4
	display->push_queue = ret;
Packit 1fb8d4
	return &ret->event;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
bool UwacHasEvent(UwacDisplay* display)
Packit 1fb8d4
{
Packit 1fb8d4
	return display->pop_queue != NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	UwacEventListItem* prevItem;
Packit 1fb8d4
	int ret;
Packit 1fb8d4
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
		return UWAC_ERROR_INVALID_DISPLAY;
Packit 1fb8d4
Packit 1fb8d4
	while (!display->pop_queue)
Packit 1fb8d4
	{
Packit 1fb8d4
		ret = UwacDisplayDispatch(display, 1 * 1000);
Packit 1fb8d4
Packit 1fb8d4
		if (ret < 0)
Packit 1fb8d4
			return UWAC_ERROR_INTERNAL;
Packit 1fb8d4
		else if (ret == 0)
Packit 1fb8d4
			return UWAC_ERROR_CLOSED;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	prevItem = display->pop_queue->head;
Packit 1fb8d4
	*event = display->pop_queue->event;
Packit 1fb8d4
	free(display->pop_queue);
Packit 1fb8d4
	display->pop_queue = prevItem;
Packit 1fb8d4
Packit 1fb8d4
	if (prevItem)
Packit 1fb8d4
		prevItem->tail = NULL;
Packit 1fb8d4
	else
Packit 1fb8d4
		display->push_queue = NULL;
Packit 1fb8d4
Packit 1fb8d4
	return UWAC_SUCCESS;
Packit 1fb8d4
}