Blame uwac/libuwac/uwac-display.c

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