Fixed NULL pointer dereferences.

This commit is contained in:
Armin Novak 2016-10-19 11:05:12 +02:00
parent 92befb0171
commit ab733d76e5
2 changed files with 507 additions and 327 deletions

View File

@ -41,7 +41,8 @@
#define TARGET_SEAT_INTERFACE 5 #define TARGET_SEAT_INTERFACE 5
#define TARGET_XDG_VERSION 5 /* The version of xdg-shell that we implement */ #define TARGET_XDG_VERSION 5 /* The version of xdg-shell that we implement */
static const char *event_names[] = { static const char* event_names[] =
{
"new seat", "new seat",
"removed seat", "removed seat",
"new output", "new output",
@ -64,17 +65,18 @@ static const char *event_names[] = {
NULL NULL
}; };
bool uwac_default_error_handler(UwacDisplay *display, UwacReturnCode code, const char *msg, ...) { bool uwac_default_error_handler(UwacDisplay* display, UwacReturnCode code, const char* msg, ...)
{
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
vfprintf(stderr, "%s", args); vfprintf(stderr, "%s", args);
return false; return false;
} }
UwacErrorHandler uwacErrorHandler = uwac_default_error_handler; UwacErrorHandler uwacErrorHandler = uwac_default_error_handler;
void UwacInstallErrorHandler(UwacErrorHandler handler) { void UwacInstallErrorHandler(UwacErrorHandler handler)
{
if (handler) if (handler)
uwacErrorHandler = handler; uwacErrorHandler = handler;
else else
@ -82,225 +84,274 @@ void UwacInstallErrorHandler(UwacErrorHandler handler) {
} }
static void cb_shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) static void cb_shm_format(void* data, struct wl_shm* wl_shm, uint32_t format)
{ {
UwacDisplay *d = data; UwacDisplay* d = data;
if (format == WL_SHM_FORMAT_RGB565) if (format == WL_SHM_FORMAT_RGB565)
d->has_rgb565 = true; d->has_rgb565 = true;
d->shm_formats_nb++; d->shm_formats_nb++;
d->shm_formats = xrealloc((void *)d->shm_formats, sizeof(enum wl_shm_format) * d->shm_formats_nb); d->shm_formats = xrealloc((void*)d->shm_formats, sizeof(enum wl_shm_format) * d->shm_formats_nb);
d->shm_formats[d->shm_formats_nb - 1] = format; d->shm_formats[d->shm_formats_nb - 1] = format;
} }
struct wl_shm_listener shm_listener = { struct wl_shm_listener shm_listener =
{
cb_shm_format cb_shm_format
}; };
static void xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial) static void xdg_shell_ping(void* data, struct xdg_shell* shell, uint32_t serial)
{ {
xdg_shell_pong(shell, serial); xdg_shell_pong(shell, serial);
} }
static const struct xdg_shell_listener xdg_shell_listener = { static const struct xdg_shell_listener xdg_shell_listener =
{
xdg_shell_ping, xdg_shell_ping,
}; };
#ifdef BUILD_FULLSCREEN_SHELL #ifdef BUILD_FULLSCREEN_SHELL
static void fullscreen_capability(void *data, struct _wl_fullscreen_shell *_wl_fullscreen_shell, static void fullscreen_capability(void* data, struct _wl_fullscreen_shell* _wl_fullscreen_shell,
uint32_t capabilty) uint32_t capabilty)
{ {
} }
static const struct _wl_fullscreen_shell_listener fullscreen_shell_listener = { static const struct _wl_fullscreen_shell_listener fullscreen_shell_listener =
{
fullscreen_capability, fullscreen_capability,
}; };
#endif #endif
static UwacSeat *display_destroy_seat(UwacDisplay *d, uint32_t name) static UwacSeat* display_destroy_seat(UwacDisplay* d, uint32_t name)
{ {
UwacSeat *seat; UwacSeat* seat;
wl_list_for_each(seat, &d->seats, link)
wl_list_for_each(seat, &d->seats, link) { {
if (seat->seat_id == name) { if (seat->seat_id == name)
{
UwacSeatDestroy(seat); UwacSeatDestroy(seat);
return seat; return seat;
} }
} }
return NULL; return NULL;
} }
static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t id,
const char *interface, uint32_t version) const char* interface, uint32_t version)
{ {
UwacDisplay *d = data; UwacDisplay* d = data;
UwacGlobal *global; UwacGlobal* global;
global = xmalloc(sizeof * global);
global = xmalloc(sizeof *global);
global->name = id; global->name = id;
global->interface = xstrdup(interface); global->interface = xstrdup(interface);
global->version = version; global->version = version;
wl_list_insert(d->globals.prev, &global->link); wl_list_insert(d->globals.prev, &global->link);
if (strcmp(interface, "wl_compositor") == 0) { if (strcmp(interface, "wl_compositor") == 0)
d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, min(TARGET_COMPOSITOR_INTERFACE, version)); {
} else if (strcmp(interface, "wl_shm") == 0) { d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface,
min(TARGET_COMPOSITOR_INTERFACE, version));
}
else if (strcmp(interface, "wl_shm") == 0)
{
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version)); d->shm = wl_registry_bind(registry, id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version));
wl_shm_add_listener(d->shm, &shm_listener, d); wl_shm_add_listener(d->shm, &shm_listener, d);
} else if (strcmp(interface, "wl_output") == 0) { }
UwacOutput *output; else if (strcmp(interface, "wl_output") == 0)
UwacOutputNewEvent *ev; {
UwacOutput* output;
UwacOutputNewEvent* ev;
output = UwacCreateOutput(d, id, version); output = UwacCreateOutput(d, id, version);
if (!output) {
if (!output)
{
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create output\n")); assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create output\n"));
return; return;
} }
ev = (UwacOutputNewEvent *)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_OUTPUT); ev = (UwacOutputNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_OUTPUT);
if (ev) if (ev)
ev->output = output; ev->output = output;
}
} else if (strcmp(interface, "wl_seat") == 0) { else if (strcmp(interface, "wl_seat") == 0)
UwacSeatNewEvent *ev; {
UwacSeat *seat; UwacSeatNewEvent* ev;
UwacSeat* seat;
seat = UwacSeatNew(d, id, min(version, TARGET_SEAT_INTERFACE)); seat = UwacSeatNew(d, id, min(version, TARGET_SEAT_INTERFACE));
if (!seat) {
if (!seat)
{
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat\n")); assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat\n"));
return; return;
} }
ev = (UwacSeatNewEvent *)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT); ev = (UwacSeatNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT);
if (!ev) {
if (!ev)
{
assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat event\n")); assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat event\n"));
return; return;
} }
ev->seat = seat; ev->seat = seat;
} else if (strcmp(interface, "wl_data_device_manager") == 0) { }
d->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, min(TARGET_DDM_INTERFACE, version)); else if (strcmp(interface, "wl_data_device_manager") == 0)
} else if (strcmp(interface, "wl_shell") == 0) { {
d->shell = wl_registry_bind(registry, id, &wl_shell_interface, min(TARGET_SHELL_INTERFACE, version)); d->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface,
} else if (strcmp(interface, "xdg_shell") == 0) { min(TARGET_DDM_INTERFACE, version));
}
else if (strcmp(interface, "wl_shell") == 0)
{
d->shell = wl_registry_bind(registry, id, &wl_shell_interface, min(TARGET_SHELL_INTERFACE,
version));
}
else if (strcmp(interface, "xdg_shell") == 0)
{
d->xdg_shell = wl_registry_bind(registry, id, &xdg_shell_interface, 1); d->xdg_shell = wl_registry_bind(registry, id, &xdg_shell_interface, 1);
xdg_shell_use_unstable_version(d->xdg_shell, TARGET_XDG_VERSION); xdg_shell_use_unstable_version(d->xdg_shell, TARGET_XDG_VERSION);
xdg_shell_add_listener(d->xdg_shell, &xdg_shell_listener, d); xdg_shell_add_listener(d->xdg_shell, &xdg_shell_listener, d);
#if BUILD_IVI #if BUILD_IVI
} else if (strcmp(interface, "ivi_application") == 0) { }
else if (strcmp(interface, "ivi_application") == 0)
{
d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1); d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
#endif #endif
#if BUILD_FULLSCREEN_SHELL #if BUILD_FULLSCREEN_SHELL
} else if (strcmp(interface, "_wl_fullscreen_shell") == 0) { }
else if (strcmp(interface, "_wl_fullscreen_shell") == 0)
{
d->fullscreen_shell = wl_registry_bind(registry, id, &_wl_fullscreen_shell_interface, 1); d->fullscreen_shell = wl_registry_bind(registry, id, &_wl_fullscreen_shell_interface, 1);
_wl_fullscreen_shell_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d); _wl_fullscreen_shell_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d);
#endif #endif
#if 0 #if 0
} else if (strcmp(interface, "text_cursor_position") == 0) { }
else if (strcmp(interface, "text_cursor_position") == 0)
{
d->text_cursor_position = wl_registry_bind(registry, id, &text_cursor_position_interface, 1); d->text_cursor_position = wl_registry_bind(registry, id, &text_cursor_position_interface, 1);
} else if (strcmp(interface, "workspace_manager") == 0) { }
else if (strcmp(interface, "workspace_manager") == 0)
{
//init_workspace_manager(d, id); //init_workspace_manager(d, id);
} else if (strcmp(interface, "wl_subcompositor") == 0) { }
else if (strcmp(interface, "wl_subcompositor") == 0)
{
d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
#endif #endif
} }
} }
static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { static void registry_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name)
UwacDisplay *d = data; {
UwacGlobal *global; UwacDisplay* d = data;
UwacGlobal *tmp; UwacGlobal* global;
UwacGlobal* tmp;
wl_list_for_each_safe(global, tmp, &d->globals, link) { wl_list_for_each_safe(global, tmp, &d->globals, link)
{
if (global->name != name) if (global->name != name)
continue; continue;
#if 0 #if 0
if (strcmp(global->interface, "wl_output") == 0) if (strcmp(global->interface, "wl_output") == 0)
display_destroy_output(d, name); display_destroy_output(d, name);
#endif #endif
if (strcmp(global->interface, "wl_seat") == 0) { if (strcmp(global->interface, "wl_seat") == 0)
UwacSeatRemovedEvent *ev; {
UwacSeat *seat; UwacSeatRemovedEvent* ev;
UwacSeat* seat;
seat = display_destroy_seat(d, name); seat = display_destroy_seat(d, name);
ev = (UwacSeatRemovedEvent *)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT); ev = (UwacSeatRemovedEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT);
if (ev) if (ev)
ev->seat = seat; ev->seat = seat;
} }
wl_list_remove(&global->link); wl_list_remove(&global->link);
free(global->interface); free(global->interface);
free(global); free(global);
} }
} }
void UwacDestroyGlobal(UwacGlobal *global) { void UwacDestroyGlobal(UwacGlobal* global)
{
free(global->interface); free(global->interface);
wl_list_remove(&global->link); wl_list_remove(&global->link);
free(global); free(global);
} }
void *display_bind(UwacDisplay *display, uint32_t name, const struct wl_interface *interface, uint32_t version) { void* display_bind(UwacDisplay* display, uint32_t name, const struct wl_interface* interface,
uint32_t version)
{
return wl_registry_bind(display->registry, name, interface, version); return wl_registry_bind(display->registry, name, interface, version);
} }
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener =
{
registry_handle_global, registry_handle_global,
registry_handle_global_remove registry_handle_global_remove
}; };
int UwacDisplayWatchFd(UwacDisplay *display, int fd, uint32_t events, UwacTask *task) { int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task)
{
struct epoll_event ep; struct epoll_event ep;
ep.events = events; ep.events = events;
ep.data.ptr = task; ep.data.ptr = task;
return epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep); return epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
} }
void UwacDisplayUnwatchFd(UwacDisplay *display, int fd) { void UwacDisplayUnwatchFd(UwacDisplay* display, int fd)
{
epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL); epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
} }
static void display_exit(UwacDisplay *display) { static void display_exit(UwacDisplay* display)
{
display->running = false; display->running = false;
} }
static void display_dispatch_events(UwacTask *task, uint32_t events) static void display_dispatch_events(UwacTask* task, uint32_t events)
{ {
UwacDisplay *display = container_of(task, UwacDisplay, dispatch_fd_task); UwacDisplay* display = container_of(task, UwacDisplay, dispatch_fd_task);
struct epoll_event ep; struct epoll_event ep;
int ret; int ret;
display->display_fd_events = events; display->display_fd_events = events;
if ((events & EPOLLERR) || (events & EPOLLHUP)) { if ((events & EPOLLERR) || (events & EPOLLHUP))
{
display_exit(display); display_exit(display);
return; return;
} }
if (events & EPOLLIN) { if (events & EPOLLIN)
{
ret = wl_display_dispatch(display->display); ret = wl_display_dispatch(display->display);
if (ret == -1) {
if (ret == -1)
{
display_exit(display); display_exit(display);
return; return;
} }
} }
if (events & EPOLLOUT) { if (events & EPOLLOUT)
{
ret = wl_display_flush(display->display); ret = wl_display_flush(display->display);
if (ret == 0) {
if (ret == 0)
{
ep.events = EPOLLIN | EPOLLERR | EPOLLHUP; ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
ep.data.ptr = &display->dispatch_fd_task; ep.data.ptr = &display->dispatch_fd_task;
epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep); epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep);
} else if (ret == -1 && errno != EAGAIN) { }
else if (ret == -1 && errno != EAGAIN)
{
display_exit(display); display_exit(display);
return; return;
} }
@ -308,11 +359,13 @@ static void display_dispatch_events(UwacTask *task, uint32_t events)
} }
UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err) { UwacDisplay* UwacOpenDisplay(const char* name, UwacReturnCode* err)
UwacDisplay *ret; {
UwacDisplay* ret;
ret = (UwacDisplay*)calloc(1, sizeof(*ret));
ret = (UwacDisplay *)calloc(1, sizeof(*ret)); if (!ret)
if (!ret) { {
*err = UWAC_ERROR_NOMEMORY; *err = UWAC_ERROR_NOMEMORY;
return NULL; return NULL;
} }
@ -321,38 +374,46 @@ UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err) {
wl_list_init(&ret->seats); wl_list_init(&ret->seats);
wl_list_init(&ret->outputs); wl_list_init(&ret->outputs);
wl_list_init(&ret->windows); wl_list_init(&ret->windows);
ret->display = wl_display_connect(name); ret->display = wl_display_connect(name);
if (ret->display == NULL) {
if (ret->display == NULL)
{
fprintf(stderr, "failed to connect to Wayland display %s: %m\n", name); fprintf(stderr, "failed to connect to Wayland display %s: %m\n", name);
*err = UWAC_ERROR_UNABLE_TO_CONNECT; *err = UWAC_ERROR_UNABLE_TO_CONNECT;
goto out_free; goto out_free;
} }
ret->epoll_fd = uwac_os_epoll_create_cloexec(); ret->epoll_fd = uwac_os_epoll_create_cloexec();
if (ret->epoll_fd < 0) {
if (ret->epoll_fd < 0)
{
*err = UWAC_NOT_ENOUGH_RESOURCES; *err = UWAC_NOT_ENOUGH_RESOURCES;
goto out_disconnect; goto out_disconnect;
} }
ret->display_fd = wl_display_get_fd(ret->display); ret->display_fd = wl_display_get_fd(ret->display);
ret->registry = wl_display_get_registry(ret->display); ret->registry = wl_display_get_registry(ret->display);
if (!ret->registry) {
if (!ret->registry)
{
*err = UWAC_ERROR_NOMEMORY; *err = UWAC_ERROR_NOMEMORY;
goto out_close_epoll; goto out_close_epoll;
} }
wl_registry_add_listener(ret->registry, &registry_listener, ret); wl_registry_add_listener(ret->registry, &registry_listener, ret);
if ((wl_display_roundtrip(ret->display) < 0) || (wl_display_roundtrip(ret->display) < 0)) { if ((wl_display_roundtrip(ret->display) < 0) || (wl_display_roundtrip(ret->display) < 0))
{
uwacErrorHandler(ret, UWAC_ERROR_UNABLE_TO_CONNECT, "Failed to process Wayland connection: %m\n"); uwacErrorHandler(ret, UWAC_ERROR_UNABLE_TO_CONNECT, "Failed to process Wayland connection: %m\n");
*err = UWAC_ERROR_UNABLE_TO_CONNECT; *err = UWAC_ERROR_UNABLE_TO_CONNECT;
goto out_free_registry; goto out_free_registry;
} }
ret->dispatch_fd_task.run = display_dispatch_events; ret->dispatch_fd_task.run = display_dispatch_events;
if (UwacDisplayWatchFd(ret, ret->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP, &ret->dispatch_fd_task) < 0) {
if (UwacDisplayWatchFd(ret, ret->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP,
&ret->dispatch_fd_task) < 0)
{
uwacErrorHandler(ret, UWAC_ERROR_INTERNAL, "unable to watch display fd: %m\n"); uwacErrorHandler(ret, UWAC_ERROR_INTERNAL, "unable to watch display fd: %m\n");
*err = UWAC_ERROR_INTERNAL; *err = UWAC_ERROR_INTERNAL;
goto out_free_registry; goto out_free_registry;
@ -361,7 +422,6 @@ UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err) {
ret->running = true; ret->running = true;
ret->last_error = *err = UWAC_SUCCESS; ret->last_error = *err = UWAC_SUCCESS;
return ret; return ret;
out_free_registry: out_free_registry:
wl_registry_destroy(ret->registry); wl_registry_destroy(ret->registry);
out_close_epoll: out_close_epoll:
@ -373,28 +433,33 @@ out_free:
return NULL; return NULL;
} }
int UwacDisplayDispatch(UwacDisplay *display, int timeout) { int UwacDisplayDispatch(UwacDisplay* display, int timeout)
{
int ret, count, i; int ret, count, i;
UwacTask *task; UwacTask* task;
struct epoll_event ep[16]; struct epoll_event ep[16];
wl_display_dispatch_pending(display->display); wl_display_dispatch_pending(display->display);
if (!display->running) if (!display->running)
return 0; return 0;
ret = wl_display_flush(display->display); ret = wl_display_flush(display->display);
if (ret < 0 && errno == EAGAIN) {
if (ret < 0 && errno == EAGAIN)
{
ep[0].events = (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP); ep[0].events = (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP);
ep[0].data.ptr = &display->dispatch_fd_task; ep[0].data.ptr = &display->dispatch_fd_task;
epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep[0]); epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep[0]);
} else if (ret < 0) { }
else if (ret < 0)
{
return -1; return -1;
} }
count = epoll_wait(display->epoll_fd, ep, ARRAY_LENGTH(ep), timeout); count = epoll_wait(display->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
for (i = 0; i < count; i++) {
for (i = 0; i < count; i++)
{
task = ep[i].data.ptr; task = ep[i].data.ptr;
task->run(task, ep[i].events); task->run(task, ep[i].events);
} }
@ -404,74 +469,85 @@ int UwacDisplayDispatch(UwacDisplay *display, int timeout) {
UwacReturnCode UwacDisplayGetLastError(const UwacDisplay *display) { UwacReturnCode UwacDisplayGetLastError(const UwacDisplay* display)
{
return display->last_error; return display->last_error;
} }
UwacReturnCode UwacCloseDisplay(UwacDisplay **pdisplay) { UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay)
UwacDisplay *display; {
UwacSeat *seat, *tmpSeat; UwacDisplay* display;
UwacWindow *window, *tmpWindow; UwacSeat* seat, *tmpSeat;
UwacOutput *output, *tmpOutput; UwacWindow* window, *tmpWindow;
UwacGlobal *global, *tmpGlobal; UwacOutput* output, *tmpOutput;
UwacGlobal* global, *tmpGlobal;
assert(pdisplay); assert(pdisplay);
display = *pdisplay; display = *pdisplay;
if (!display) if (!display)
return UWAC_ERROR_INVALID_DISPLAY; return UWAC_ERROR_INVALID_DISPLAY;
/* destroy windows */ /* destroy windows */
wl_list_for_each_safe(window, tmpWindow, &display->windows, link) { wl_list_for_each_safe(window, tmpWindow, &display->windows, link)
{
UwacDestroyWindow(&window); UwacDestroyWindow(&window);
} }
/* destroy seats */ /* destroy seats */
wl_list_for_each_safe(seat, tmpSeat, &display->seats, link) { wl_list_for_each_safe(seat, tmpSeat, &display->seats, link)
{
UwacSeatDestroy(seat); UwacSeatDestroy(seat);
} }
/* destroy output */ /* destroy output */
wl_list_for_each_safe(output, tmpOutput, &display->outputs, link) { wl_list_for_each_safe(output, tmpOutput, &display->outputs, link)
{
UwacDestroyOutput(output); UwacDestroyOutput(output);
} }
/* destroy globals */ /* destroy globals */
wl_list_for_each_safe(global, tmpGlobal, &display->globals, link) { wl_list_for_each_safe(global, tmpGlobal, &display->globals, link)
{
UwacDestroyGlobal(global); UwacDestroyGlobal(global);
} }
if (display->compositor) if (display->compositor)
wl_compositor_destroy(display->compositor); wl_compositor_destroy(display->compositor);
#ifdef BUILD_FULLSCREEN_SHELL #ifdef BUILD_FULLSCREEN_SHELL
if (display->fullscreen_shell) if (display->fullscreen_shell)
_wl_fullscreen_shell_destroy(display->fullscreen_shell); _wl_fullscreen_shell_destroy(display->fullscreen_shell);
#endif #endif
#ifdef BUILD_IVI #ifdef BUILD_IVI
if (display->ivi_application) if (display->ivi_application)
ivi_application_destroy(display->ivi_application); ivi_application_destroy(display->ivi_application);
#endif #endif
if (display->xdg_shell) if (display->xdg_shell)
xdg_shell_destroy(display->xdg_shell); xdg_shell_destroy(display->xdg_shell);
if (display->shell) if (display->shell)
wl_shell_destroy(display->shell); wl_shell_destroy(display->shell);
if (display->shm) if (display->shm)
wl_shm_destroy(display->shm); wl_shm_destroy(display->shm);
if (display->subcompositor) if (display->subcompositor)
wl_subcompositor_destroy(display->subcompositor); wl_subcompositor_destroy(display->subcompositor);
if (display->data_device_manager) if (display->data_device_manager)
wl_data_device_manager_destroy(display->data_device_manager); wl_data_device_manager_destroy(display->data_device_manager);
free(display->shm_formats); free(display->shm_formats);
wl_registry_destroy(display->registry); wl_registry_destroy(display->registry);
close(display->epoll_fd); close(display->epoll_fd);
wl_display_disconnect(display->display); wl_display_disconnect(display->display);
/* cleanup the event queue */ /* cleanup the event queue */
while (display->push_queue) { while (display->push_queue)
UwacEventListItem *item = display->push_queue; {
UwacEventListItem* item = display->push_queue;
display->push_queue = item->tail; display->push_queue = item->tail;
free(item); free(item);
} }
@ -481,11 +557,13 @@ UwacReturnCode UwacCloseDisplay(UwacDisplay **pdisplay) {
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
int UwacDisplayGetFd(UwacDisplay *display) { int UwacDisplayGetFd(UwacDisplay* display)
{
return display->epoll_fd; return display->epoll_fd;
} }
static const char *errorStrings[] = { static const char* errorStrings[] =
{
"success", "success",
"out of memory error", "out of memory error",
"unable to connect to wayland display", "unable to connect to wayland display",
@ -498,37 +576,44 @@ static const char *errorStrings[] = {
"internal error", "internal error",
}; };
const char *UwacErrorString(UwacReturnCode error) { const char* UwacErrorString(UwacReturnCode error)
{
if (error < UWAC_SUCCESS || error >= UWAC_ERROR_LAST) if (error < UWAC_SUCCESS || error >= UWAC_ERROR_LAST)
return "invalid error code"; return "invalid error code";
return errorStrings[error]; return errorStrings[error];
} }
UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay *display, const char *name, uint32_t *version) { UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay* display, const char* name,
const UwacGlobal *global; uint32_t* version)
{
const UwacGlobal* global;
if (!display) if (!display)
return UWAC_ERROR_INVALID_DISPLAY; return UWAC_ERROR_INVALID_DISPLAY;
wl_list_for_each(global, &display->globals, link) { wl_list_for_each(global, &display->globals, link)
if (strcmp(global->interface, name) == 0) { {
if (strcmp(global->interface, name) == 0)
{
if (version) if (version)
*version = global->version; *version = global->version;
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
} }
return UWAC_NOT_FOUND; return UWAC_NOT_FOUND;
} }
uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay *display) { uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display)
if (!display) { {
display->last_error = UWAC_ERROR_INVALID_DISPLAY; if (!display)
{
return 0; return 0;
} }
if (!display->shm) { if (!display->shm)
{
display->last_error = UWAC_NOT_FOUND; display->last_error = UWAC_NOT_FOUND;
return 0; return 0;
} }
@ -538,28 +623,35 @@ uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay *display) {
} }
UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay *display, enum wl_shm_format *formats, int formats_size, int *filled) { UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay* display, enum wl_shm_format* formats,
int formats_size, int* filled)
{
if (!display) if (!display)
return UWAC_ERROR_INVALID_DISPLAY; return UWAC_ERROR_INVALID_DISPLAY;
*filled = min(display->shm_formats_nb, formats_size); *filled = min(display->shm_formats_nb, formats_size);
memcpy(formats, (const void *)display->shm_formats, *filled * sizeof(enum wl_shm_format)); memcpy(formats, (const void*)display->shm_formats, *filled * sizeof(enum wl_shm_format));
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
uint32_t UwacDisplayGetNbOutputs(UwacDisplay *display) { uint32_t UwacDisplayGetNbOutputs(UwacDisplay* display)
{
return wl_list_length(&display->outputs); return wl_list_length(&display->outputs);
} }
UwacOutput *UwacDisplayGetOutput(UwacDisplay *display, int index) { UwacOutput* UwacDisplayGetOutput(UwacDisplay* display, int index)
struct wl_list *l; {
struct wl_list* l;
int i; int i;
if (!display)
return NULL;
for (i = 0, l = &display->outputs; l && i < index; i++, l = l->next) for (i = 0, l = &display->outputs; l && i < index; i++, l = l->next)
; ;
if (!l) { if (!l)
{
display->last_error = UWAC_NOT_FOUND; display->last_error = UWAC_NOT_FOUND;
return NULL; return NULL;
} }
@ -568,51 +660,62 @@ UwacOutput *UwacDisplayGetOutput(UwacDisplay *display, int index) {
return container_of(l, UwacOutput, link); return container_of(l, UwacOutput, link);
} }
UwacReturnCode UwacOutputGetResolution(UwacOutput *output, UwacSize *resolution) { UwacReturnCode UwacOutputGetResolution(UwacOutput* output, UwacSize* resolution)
{
*resolution = output->resolution; *resolution = output->resolution;
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
UwacEvent *UwacDisplayNewEvent(UwacDisplay *display, int type) { UwacEvent* UwacDisplayNewEvent(UwacDisplay* display, int type)
UwacEventListItem *ret; {
UwacEventListItem* ret;
if (!display) { if (!display)
display->last_error = UWAC_ERROR_INVALID_DISPLAY; {
return 0; return 0;
} }
ret = zalloc(sizeof(UwacEventListItem)); ret = zalloc(sizeof(UwacEventListItem));
if (!ret) {
assert(uwacErrorHandler(display, UWAC_ERROR_NOMEMORY, "unable to allocate a '%s' event", event_names[type])); if (!ret)
{
assert(uwacErrorHandler(display, UWAC_ERROR_NOMEMORY, "unable to allocate a '%s' event",
event_names[type]));
display->last_error = UWAC_ERROR_NOMEMORY; display->last_error = UWAC_ERROR_NOMEMORY;
return 0; return 0;
} }
ret->event.type = type; ret->event.type = type;
ret->tail = display->push_queue; ret->tail = display->push_queue;
if (ret->tail) if (ret->tail)
ret->tail->head = ret; ret->tail->head = ret;
else else
display->pop_queue = ret; display->pop_queue = ret;
display->push_queue = ret; display->push_queue = ret;
return &ret->event; return &ret->event;
} }
bool UwacHasEvent(UwacDisplay *display) { bool UwacHasEvent(UwacDisplay* display)
{
return display->pop_queue != NULL; return display->pop_queue != NULL;
} }
UwacReturnCode UwacNextEvent(UwacDisplay *display, UwacEvent *event) { UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event)
UwacEventListItem *prevItem; {
UwacEventListItem* prevItem;
int ret; int ret;
if (!display) if (!display)
return UWAC_ERROR_INVALID_DISPLAY; return UWAC_ERROR_INVALID_DISPLAY;
while (!display->pop_queue) { while (!display->pop_queue)
{
ret = UwacDisplayDispatch(display, 1 * 1000); ret = UwacDisplayDispatch(display, 1 * 1000);
if (ret < 0) if (ret < 0)
return UWAC_ERROR_INTERNAL; return UWAC_ERROR_INTERNAL;
else if (ret == 0) else if (ret == 0)
@ -623,9 +726,11 @@ UwacReturnCode UwacNextEvent(UwacDisplay *display, UwacEvent *event) {
*event = display->pop_queue->event; *event = display->pop_queue->event;
free(display->pop_queue); free(display->pop_queue);
display->pop_queue = prevItem; display->pop_queue = prevItem;
if (prevItem) if (prevItem)
prevItem->tail = NULL; prevItem->tail = NULL;
else else
display->push_queue = NULL; display->push_queue = NULL;
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }

View File

@ -35,8 +35,10 @@
#define UWAC_INITIAL_BUFFERS 3 #define UWAC_INITIAL_BUFFERS 3
static int bppFromShmFormat(enum wl_shm_format format) { static int bppFromShmFormat(enum wl_shm_format format)
switch (format) { {
switch (format)
{
case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_ARGB8888:
case WL_SHM_FORMAT_XRGB8888: case WL_SHM_FORMAT_XRGB8888:
default: default:
@ -45,21 +47,24 @@ static int bppFromShmFormat(enum wl_shm_format format) {
} }
static void buffer_release(void *data, struct wl_buffer *buffer) { static void buffer_release(void* data, struct wl_buffer* buffer)
UwacBuffer *uwacBuffer = (UwacBuffer *)data; {
UwacBuffer* uwacBuffer = (UwacBuffer*)data;
uwacBuffer->used = false; uwacBuffer->used = false;
} }
static const struct wl_buffer_listener buffer_listener = { static const struct wl_buffer_listener buffer_listener =
{
buffer_release buffer_release
}; };
void UwacWindowDestroyBuffers(UwacWindow *w) { void UwacWindowDestroyBuffers(UwacWindow* w)
{
int i; int i;
for (i = 0; i < w->nbuffers; i++) { for (i = 0; i < w->nbuffers; i++)
UwacBuffer *buffer = &w->buffers[i]; {
UwacBuffer* buffer = &w->buffers[i];
#ifdef HAVE_PIXMAN_REGION #ifdef HAVE_PIXMAN_REGION
pixman_region32_fini(&buffer->damage); pixman_region32_fini(&buffer->damage);
#else #else
@ -74,67 +79,77 @@ void UwacWindowDestroyBuffers(UwacWindow *w) {
} }
int UwacWindowShmAllocBuffers(UwacWindow *w, int nbuffers, int allocSize, uint32_t width, int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32_t width,
uint32_t height, enum wl_shm_format format); uint32_t height, enum wl_shm_format format);
static void xdg_handle_configure(void *data, struct xdg_surface *surface, static void xdg_handle_configure(void* data, struct xdg_surface* surface,
int32_t width, int32_t height, int32_t width, int32_t height,
struct wl_array *states, uint32_t serial) struct wl_array* states, uint32_t serial)
{ {
UwacWindow *window = (UwacWindow *)data; UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent *event; UwacConfigureEvent* event;
int ret, surfaceState; int ret, surfaceState;
enum xdg_surface_state *state; enum xdg_surface_state* state;
surfaceState = 0; surfaceState = 0;
wl_array_for_each(state, states) { wl_array_for_each(state, states)
switch (*state) { {
switch (*state)
{
case XDG_SURFACE_STATE_MAXIMIZED: case XDG_SURFACE_STATE_MAXIMIZED:
surfaceState |= UWAC_WINDOW_MAXIMIZED; surfaceState |= UWAC_WINDOW_MAXIMIZED;
break; break;
case XDG_SURFACE_STATE_FULLSCREEN: case XDG_SURFACE_STATE_FULLSCREEN:
surfaceState |= UWAC_WINDOW_FULLSCREEN; surfaceState |= UWAC_WINDOW_FULLSCREEN;
break; break;
case XDG_SURFACE_STATE_ACTIVATED: case XDG_SURFACE_STATE_ACTIVATED:
surfaceState |= UWAC_WINDOW_ACTIVATED; surfaceState |= UWAC_WINDOW_ACTIVATED;
break; break;
case XDG_SURFACE_STATE_RESIZING: case XDG_SURFACE_STATE_RESIZING:
surfaceState |= UWAC_WINDOW_RESIZING; surfaceState |= UWAC_WINDOW_RESIZING;
break; break;
default: default:
break; break;
} }
} }
window->surfaceStates = surfaceState; window->surfaceStates = surfaceState;
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
event = (UwacConfigureEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE); if (!event)
if(!event) { {
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY, "failed to allocate a configure event\n")); assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
goto ack; goto ack;
} }
event->window = window; event->window = window;
event->states = surfaceState; event->states = surfaceState;
if (width && height) {
if (width && height)
{
event->width = width; event->width = width;
event->height = height; event->height = height;
UwacWindowDestroyBuffers(window); UwacWindowDestroyBuffers(window);
window->width = width; window->width = width;
window->stride = width * bppFromShmFormat(window->format); window->stride = width * bppFromShmFormat(window->format);
window->height = height; window->height = height;
ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height, ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height,
width, height, window->format); width, height, window->format);
if (ret != UWAC_SUCCESS) {
if (ret != UWAC_SUCCESS)
{
assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n")); assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
window->drawingBuffer = window->pendingBuffer = NULL; window->drawingBuffer = window->pendingBuffer = NULL;
goto ack; goto ack;
} }
window->drawingBuffer = window->pendingBuffer = &window->buffers[0]; window->drawingBuffer = window->pendingBuffer = &window->buffers[0];
} else { }
else
{
event->width = window->width; event->width = window->width;
event->height = window->height; event->height = window->height;
} }
@ -143,198 +158,221 @@ ack:
xdg_surface_ack_configure(surface, serial); xdg_surface_ack_configure(surface, serial);
} }
static void xdg_handle_close(void *data, struct xdg_surface *xdg_surface) static void xdg_handle_close(void* data, struct xdg_surface* xdg_surface)
{ {
UwacCloseEvent *event; UwacCloseEvent* event;
UwacWindow *window = (UwacWindow *)data; UwacWindow* window = (UwacWindow*)data;
event = (UwacCloseEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE);
event = (UwacCloseEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE); if (!event)
if(!event) { {
assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL, "failed to allocate a close event\n")); assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL,
"failed to allocate a close event\n"));
return; return;
} }
event->window = window; event->window = window;
} }
static const struct xdg_surface_listener xdg_surface_listener = { static const struct xdg_surface_listener xdg_surface_listener =
{
xdg_handle_configure, xdg_handle_configure,
xdg_handle_close, xdg_handle_close,
}; };
#if BUILD_IVI #if BUILD_IVI
static void ivi_handle_configure(void *data, struct ivi_surface *surface, static void ivi_handle_configure(void* data, struct ivi_surface* surface,
int32_t width, int32_t height) int32_t width, int32_t height)
{ {
UwacWindow *window = (UwacWindow *)data; UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent *event; UwacConfigureEvent* event;
int ret; int ret;
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
if (!event)
event = (UwacConfigureEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE); {
if(!event) { assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY, "failed to allocate a configure event\n")); "failed to allocate a configure event\n"));
return; return;
} }
event->window = window; event->window = window;
event->states = 0; event->states = 0;
if (width && height) {
if (width && height)
{
event->width = width; event->width = width;
event->height = height; event->height = height;
UwacWindowDestroyBuffers(window); UwacWindowDestroyBuffers(window);
window->width = width; window->width = width;
window->stride = width * bppFromShmFormat(window->format); window->stride = width * bppFromShmFormat(window->format);
window->height = height; window->height = height;
ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height, ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height,
width, height, window->format); width, height, window->format);
if (ret != UWAC_SUCCESS) {
if (ret != UWAC_SUCCESS)
{
assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n")); assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
window->drawingBuffer = window->pendingBuffer = NULL; window->drawingBuffer = window->pendingBuffer = NULL;
return; return;
} }
window->drawingBuffer = window->pendingBuffer = &window->buffers[0]; window->drawingBuffer = window->pendingBuffer = &window->buffers[0];
} else { }
else
{
event->width = window->width; event->width = window->width;
event->height = window->height; event->height = window->height;
} }
} }
static const struct ivi_surface_listener ivi_surface_listener = { static const struct ivi_surface_listener ivi_surface_listener =
{
ivi_handle_configure, ivi_handle_configure,
}; };
#endif #endif
void shell_ping(void *data, struct wl_shell_surface *surface, uint32_t serial) void shell_ping(void* data, struct wl_shell_surface* surface, uint32_t serial)
{ {
wl_shell_surface_pong(surface, serial); wl_shell_surface_pong(surface, serial);
} }
void shell_configure(void *data, struct wl_shell_surface *surface, uint32_t edges, void shell_configure(void* data, struct wl_shell_surface* surface, uint32_t edges,
int32_t width, int32_t height) int32_t width, int32_t height)
{ {
UwacWindow *window = (UwacWindow *)data; UwacWindow* window = (UwacWindow*)data;
UwacConfigureEvent *event; UwacConfigureEvent* event;
int ret; int ret;
event = (UwacConfigureEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE);
event = (UwacConfigureEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE); if (!event)
if(!event) { {
assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY, "failed to allocate a configure event\n")); assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY,
"failed to allocate a configure event\n"));
return; return;
} }
event->window = window; event->window = window;
event->states = 0; event->states = 0;
if (width && height) {
if (width && height)
{
event->width = width; event->width = width;
event->height = height; event->height = height;
UwacWindowDestroyBuffers(window); UwacWindowDestroyBuffers(window);
window->width = width; window->width = width;
window->stride = width * bppFromShmFormat(window->format); window->stride = width * bppFromShmFormat(window->format);
window->height = height; window->height = height;
ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height, ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height,
width, height, window->format); width, height, window->format);
if (ret != UWAC_SUCCESS) {
if (ret != UWAC_SUCCESS)
{
assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n")); assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
window->drawingBuffer = window->pendingBuffer = NULL; window->drawingBuffer = window->pendingBuffer = NULL;
return; return;
} }
window->drawingBuffer = window->pendingBuffer = &window->buffers[0]; window->drawingBuffer = window->pendingBuffer = &window->buffers[0];
} else { }
else
{
event->width = window->width; event->width = window->width;
event->height = window->height; event->height = window->height;
} }
} }
void shell_popup_done(void *data, struct wl_shell_surface *surface) void shell_popup_done(void* data, struct wl_shell_surface* surface)
{ {
} }
static const struct wl_shell_surface_listener shell_listener = { static const struct wl_shell_surface_listener shell_listener =
{
shell_ping, shell_ping,
shell_configure, shell_configure,
shell_popup_done shell_popup_done
}; };
int UwacWindowShmAllocBuffers(UwacWindow *w, int nbuffers, int allocSize, uint32_t width, int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32_t width,
uint32_t height, enum wl_shm_format format) uint32_t height, enum wl_shm_format format)
{ {
int ret = UWAC_SUCCESS; int ret = UWAC_SUCCESS;
UwacBuffer *newBuffers; UwacBuffer* newBuffers;
int i, fd; int i, fd;
void *data; void* data;
struct wl_shm_pool *pool; struct wl_shm_pool* pool;
newBuffers = realloc(w->buffers, (w->nbuffers + nbuffers) * sizeof(UwacBuffer)); newBuffers = realloc(w->buffers, (w->nbuffers + nbuffers) * sizeof(UwacBuffer));
if (!newBuffers) if (!newBuffers)
return UWAC_ERROR_NOMEMORY; return UWAC_ERROR_NOMEMORY;
w->buffers = newBuffers; w->buffers = newBuffers;
memset(w->buffers + w->nbuffers, 0, sizeof(UwacBuffer) * nbuffers); memset(w->buffers + w->nbuffers, 0, sizeof(UwacBuffer) * nbuffers);
fd = uwac_create_anonymous_file(allocSize * nbuffers); fd = uwac_create_anonymous_file(allocSize * nbuffers);
if (fd < 0) {
if (fd < 0)
{
return UWAC_ERROR_INTERNAL; return UWAC_ERROR_INTERNAL;
} }
data = mmap(NULL, allocSize * nbuffers, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data = mmap(NULL, allocSize * nbuffers, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
if (data == MAP_FAILED)
{
ret = UWAC_ERROR_NOMEMORY; ret = UWAC_ERROR_NOMEMORY;
goto error_mmap; goto error_mmap;
} }
pool = wl_shm_create_pool(w->display->shm, fd, allocSize * nbuffers); pool = wl_shm_create_pool(w->display->shm, fd, allocSize * nbuffers);
if (!pool) {
if (!pool)
{
ret = UWAC_ERROR_NOMEMORY; ret = UWAC_ERROR_NOMEMORY;
goto error_mmap; goto error_mmap;
} }
for (i = 0; i < nbuffers; i++) { for (i = 0; i < nbuffers; i++)
UwacBuffer *buffer = &w->buffers[w->nbuffers + i]; {
UwacBuffer* buffer = &w->buffers[w->nbuffers + i];
#ifdef HAVE_PIXMAN_REGION #ifdef HAVE_PIXMAN_REGION
pixman_region32_init(&buffer->damage); pixman_region32_init(&buffer->damage);
#else #else
region16_init(&buffer->damage); region16_init(&buffer->damage);
#endif #endif
buffer->data = data + (allocSize * i); buffer->data = data + (allocSize * i);
buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride,
buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format); format);
wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer); wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer);
} }
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
w->nbuffers += nbuffers; w->nbuffers += nbuffers;
error_mmap: error_mmap:
close(fd); close(fd);
return ret; return ret;
} }
UwacBuffer *UwacWindowFindFreeBuffer(UwacWindow *w) { UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w)
{
int i, ret; int i, ret;
for (i = 0; i < w->nbuffers; i++) { for (i = 0; i < w->nbuffers; i++)
if (!w->buffers[i].used) { {
if (!w->buffers[i].used)
{
w->buffers[i].used = true; w->buffers[i].used = true;
return &w->buffers[i]; return &w->buffers[i];
} }
} }
ret = UwacWindowShmAllocBuffers(w, 2, w->stride * w->height, w->width, w->height, w->format); ret = UwacWindowShmAllocBuffers(w, 2, w->stride * w->height, w->width, w->height, w->format);
if (ret != UWAC_SUCCESS) {
if (ret != UWAC_SUCCESS)
{
w->display->last_error = ret; w->display->last_error = ret;
return NULL; return NULL;
} }
@ -344,17 +382,21 @@ UwacBuffer *UwacWindowFindFreeBuffer(UwacWindow *w) {
} }
UwacWindow *UwacCreateWindowShm(UwacDisplay *display, uint32_t width, uint32_t height, enum wl_shm_format format) { UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t height,
UwacWindow *w; enum wl_shm_format format)
{
UwacWindow* w;
int allocSize, ret; int allocSize, ret;
if (!display) { if (!display)
display->last_error = UWAC_ERROR_INVALID_DISPLAY; {
return NULL; return NULL;
} }
w = zalloc(sizeof(*w)); w = zalloc(sizeof(*w));
if (!w) {
if (!w)
{
display->last_error = UWAC_ERROR_NOMEMORY; display->last_error = UWAC_ERROR_NOMEMORY;
return NULL; return NULL;
} }
@ -365,60 +407,65 @@ UwacWindow *UwacCreateWindowShm(UwacDisplay *display, uint32_t width, uint32_t h
w->height = height; w->height = height;
w->stride = width * bppFromShmFormat(format); w->stride = width * bppFromShmFormat(format);
allocSize = w->stride * height; allocSize = w->stride * height;
ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format); ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format);
if (ret != UWAC_SUCCESS) {
if (ret != UWAC_SUCCESS)
{
display->last_error = ret; display->last_error = ret;
goto out_error_free; goto out_error_free;
} }
w->buffers[0].used = true; w->buffers[0].used = true;
w->drawingBuffer = &w->buffers[0]; w->drawingBuffer = &w->buffers[0];
w->surface = wl_compositor_create_surface(display->compositor); w->surface = wl_compositor_create_surface(display->compositor);
if (!w->surface) {
if (!w->surface)
{
display->last_error = UWAC_ERROR_NOMEMORY; display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_surface; goto out_error_surface;
} }
wl_surface_set_user_data(w->surface, w); wl_surface_set_user_data(w->surface, w);
if (display->xdg_shell) { if (display->xdg_shell)
{
w->xdg_surface = xdg_shell_get_xdg_surface(display->xdg_shell, w->surface); w->xdg_surface = xdg_shell_get_xdg_surface(display->xdg_shell, w->surface);
if (!w->xdg_surface) {
if (!w->xdg_surface)
{
display->last_error = UWAC_ERROR_NOMEMORY; display->last_error = UWAC_ERROR_NOMEMORY;
goto out_error_shell; goto out_error_shell;
} }
assert(w->xdg_surface); assert(w->xdg_surface);
xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w); xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
#if BUILD_IVI #if BUILD_IVI
} else if (display->ivi_application) { }
else if (display->ivi_application)
{
w->ivi_surface = ivi_application_surface_create(display->ivi_application, 1, w->surface); w->ivi_surface = ivi_application_surface_create(display->ivi_application, 1, w->surface);
assert(w->ivi_surface);
assert (w->ivi_surface);
ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w); ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
#endif #endif
#if BUILD_FULLSCREEN_SHELL #if BUILD_FULLSCREEN_SHELL
} else if (display->fullscreen_shell) { }
else if (display->fullscreen_shell)
{
_wl_fullscreen_shell_present_surface(display->fullscreen_shell, w->surface, _wl_fullscreen_shell_present_surface(display->fullscreen_shell, w->surface,
_WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER, NULL); _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER, NULL);
#endif #endif
} else { }
else
{
w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface); w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
assert(w->shell_surface); assert(w->shell_surface);
wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w); wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w);
wl_shell_surface_set_toplevel(w->shell_surface); wl_shell_surface_set_toplevel(w->shell_surface);
} }
wl_list_insert(display->windows.prev, &w->link); wl_list_insert(display->windows.prev, &w->link);
display->last_error = UWAC_SUCCESS; display->last_error = UWAC_SUCCESS;
return w; return w;
out_error_shell: out_error_shell:
wl_surface_destroy(w->surface); wl_surface_destroy(w->surface);
out_error_surface: out_error_surface:
@ -429,11 +476,10 @@ out_error_free:
} }
UwacReturnCode UwacDestroyWindow(UwacWindow **pwindow) { UwacReturnCode UwacDestroyWindow(UwacWindow** pwindow)
UwacWindow *w; {
UwacWindow* w;
assert (pwindow); assert(pwindow);
w = *pwindow; w = *pwindow;
UwacWindowDestroyBuffers(w); UwacWindowDestroyBuffers(w);
@ -442,9 +488,12 @@ UwacReturnCode UwacDestroyWindow(UwacWindow **pwindow) {
if (w->xdg_surface) if (w->xdg_surface)
xdg_surface_destroy(w->xdg_surface); xdg_surface_destroy(w->xdg_surface);
#if BUILD_IVI #if BUILD_IVI
if (w->ivi_surface) if (w->ivi_surface)
ivi_surface_destroy(w->ivi_surface); ivi_surface_destroy(w->ivi_surface);
#endif #endif
if (w->opaque_region) if (w->opaque_region)
@ -456,13 +505,12 @@ UwacReturnCode UwacDestroyWindow(UwacWindow **pwindow) {
wl_surface_destroy(w->surface); wl_surface_destroy(w->surface);
wl_list_remove(&w->link); wl_list_remove(&w->link);
free(w); free(w);
*pwindow = NULL; *pwindow = NULL;
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height) uint32_t height)
{ {
assert(window); assert(window);
@ -471,6 +519,7 @@ UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow *window, uint32_t x, uint32_
wl_region_destroy(window->opaque_region); wl_region_destroy(window->opaque_region);
window->opaque_region = wl_compositor_create_region(window->display->compositor); window->opaque_region = wl_compositor_create_region(window->display->compositor);
if (!window->opaque_region) if (!window->opaque_region)
return UWAC_ERROR_NOMEMORY; return UWAC_ERROR_NOMEMORY;
@ -479,13 +528,16 @@ UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow *window, uint32_t x, uint32_
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
UwacReturnCode UwacWindowSetInputRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
assert(window); assert(window);
if (window->input_region) if (window->input_region)
wl_region_destroy(window->input_region); wl_region_destroy(window->input_region);
window->input_region = wl_compositor_create_region(window->display->compositor); window->input_region = wl_compositor_create_region(window->display->compositor);
if (!window->input_region) if (!window->input_region)
return UWAC_ERROR_NOMEMORY; return UWAC_ERROR_NOMEMORY;
@ -495,35 +547,41 @@ UwacReturnCode UwacWindowSetInputRegion(UwacWindow *window, uint32_t x, uint32_t
} }
void *UwacWindowGetDrawingBuffer(UwacWindow *window) { void* UwacWindowGetDrawingBuffer(UwacWindow* window)
{
return window->drawingBuffer->data; return window->drawingBuffer->data;
} }
static void frame_done_cb(void *data, struct wl_callback *callback, uint32_t time); static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time);
static const struct wl_callback_listener frame_listener = { static const struct wl_callback_listener frame_listener =
{
frame_done_cb frame_done_cb
}; };
static void UwacSubmitBufferPtr(UwacWindow *window, UwacBuffer *buffer) { static void UwacSubmitBufferPtr(UwacWindow* window, UwacBuffer* buffer)
{
UINT32 nrects, i; UINT32 nrects, i;
#ifdef HAVE_PIXMAN_REGION #ifdef HAVE_PIXMAN_REGION
const pixman_box32_t *box; const pixman_box32_t* box;
#else #else
const RECTANGLE_16 *box; const RECTANGLE_16* box;
#endif #endif
wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0); wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0);
#ifdef HAVE_PIXMAN_REGION #ifdef HAVE_PIXMAN_REGION
box = pixman_region32_rectangles(&buffer->damage, &nrects); box = pixman_region32_rectangles(&buffer->damage, &nrects);
for (i = 0; i < nrects; i++, box++) for (i = 0; i < nrects; i++, box++)
wl_surface_damage(window->surface, box->x1, box->y1, (box->x2 - box->x1), (box->y2 - box->y1)); wl_surface_damage(window->surface, box->x1, box->y1, (box->x2 - box->x1), (box->y2 - box->y1));
#else #else
box = region16_rects(&buffer->damage, &nrects); box = region16_rects(&buffer->damage, &nrects);
for (i = 0; i < nrects; i++, box++) for (i = 0; i < nrects; i++, box++)
wl_surface_damage(window->surface, box->left, box->top, (box->right - box->left), (box->bottom - box->top)); wl_surface_damage(window->surface, box->left, box->top, (box->right - box->left),
(box->bottom - box->top));
#endif #endif
if (window->frame_callback) if (window->frame_callback)
@ -531,9 +589,7 @@ static void UwacSubmitBufferPtr(UwacWindow *window, UwacBuffer *buffer) {
window->frame_callback = wl_surface_frame(window->surface); window->frame_callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->frame_callback, &frame_listener, window); wl_callback_add_listener(window->frame_callback, &frame_listener, window);
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
#ifdef HAVE_PIXMAN_REGION #ifdef HAVE_PIXMAN_REGION
pixman_region32_clear(&buffer->damage); pixman_region32_clear(&buffer->damage);
#else #else
@ -542,24 +598,32 @@ static void UwacSubmitBufferPtr(UwacWindow *window, UwacBuffer *buffer) {
} }
static void frame_done_cb(void *data, struct wl_callback *callback, uint32_t time) { static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time)
UwacWindow *window = (UwacWindow *)data; {
UwacFrameDoneEvent *event; UwacWindow* window = (UwacWindow*)data;
UwacFrameDoneEvent* event;
window->pendingBuffer = NULL; window->pendingBuffer = NULL;
event = (UwacFrameDoneEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE); event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
if(event)
if (event)
event->window = window; event->window = window;
} }
UwacReturnCode UwacWindowAddDamage(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width,
uint32_t height)
{
#ifdef HAVE_PIXMAN_REGION #ifdef HAVE_PIXMAN_REGION
if (!pixman_region32_union_rect(&window->drawingBuffer->damage, &window->drawingBuffer->damage, x, y, width, height))
if (!pixman_region32_union_rect(&window->drawingBuffer->damage, &window->drawingBuffer->damage, x,
y, width, height))
#else #else
RECTANGLE_16 box; RECTANGLE_16 box;
box.left = x; box.top = y;
box.right = x + width; box.bottom = y + height; box.left = x;
box.top = y;
box.right = x + width;
box.bottom = y + height;
if (!region16_union_rect(&window->drawingBuffer->damage, &window->drawingBuffer->damage, &box)) if (!region16_union_rect(&window->drawingBuffer->damage, &window->drawingBuffer->damage, &box))
#endif #endif
@ -569,50 +633,61 @@ UwacReturnCode UwacWindowAddDamage(UwacWindow *window, uint32_t x, uint32_t y, u
} }
UwacReturnCode UwacWindowSubmitBuffer(UwacWindow *window, bool copyContentForNextFrame) { UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window, bool copyContentForNextFrame)
UwacBuffer *drawingBuffer = window->drawingBuffer; {
UwacBuffer* drawingBuffer = window->drawingBuffer;
if (window->pendingBuffer) { if (window->pendingBuffer)
{
/* we already have a pending frame, don't do anything*/ /* we already have a pending frame, don't do anything*/
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
UwacSubmitBufferPtr(window, drawingBuffer); UwacSubmitBufferPtr(window, drawingBuffer);
window->pendingBuffer = window->drawingBuffer; window->pendingBuffer = window->drawingBuffer;
window->drawingBuffer = UwacWindowFindFreeBuffer(window); window->drawingBuffer = UwacWindowFindFreeBuffer(window);
if (!window->drawingBuffer) if (!window->drawingBuffer)
return UWAC_ERROR_NOMEMORY; return UWAC_ERROR_NOMEMORY;
if (copyContentForNextFrame) { if (copyContentForNextFrame)
{
memcpy(window->drawingBuffer->data, window->pendingBuffer->data, window->stride * window->height); memcpy(window->drawingBuffer->data, window->pendingBuffer->data, window->stride * window->height);
} }
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
UwacReturnCode UwacWindowGetGeometry(UwacWindow *window, UwacSize *geometry) { UwacReturnCode UwacWindowGetGeometry(UwacWindow* window, UwacSize* geometry)
{
assert(window); assert(window);
assert(geometry); assert(geometry);
geometry->width = window->width; geometry->width = window->width;
geometry->height = window->height; geometry->height = window->height;
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
UwacReturnCode UwacWindowSetFullscreenState(UwacWindow *window, UwacOutput *output, bool isFullscreen) { UwacReturnCode UwacWindowSetFullscreenState(UwacWindow* window, UwacOutput* output,
if (window->xdg_surface) { bool isFullscreen)
if (isFullscreen) { {
if (window->xdg_surface)
{
if (isFullscreen)
{
xdg_surface_set_fullscreen(window->xdg_surface, output ? output->output : NULL); xdg_surface_set_fullscreen(window->xdg_surface, output ? output->output : NULL);
} else { }
else
{
xdg_surface_unset_fullscreen(window->xdg_surface); xdg_surface_unset_fullscreen(window->xdg_surface);
} }
} }
return UWAC_SUCCESS; return UWAC_SUCCESS;
} }
void UwacWindowSetTitle(UwacWindow *window, const char *name) { void UwacWindowSetTitle(UwacWindow* window, const char* name)
{
if (window->xdg_surface) if (window->xdg_surface)
xdg_surface_set_title(window->xdg_surface, name); xdg_surface_set_title(window->xdg_surface, name);
else if (window->shell_surface) else if (window->shell_surface)