22 #include "uwac-priv.h"
23 #include "uwac-utils.h"
33 #include <sys/epoll.h>
36 #include "wayland-cursor.h"
38 #define TARGET_COMPOSITOR_INTERFACE 3U
39 #define TARGET_SHM_INTERFACE 1U
40 #define TARGET_SHELL_INTERFACE 1U
41 #define TARGET_DDM_INTERFACE 1U
42 #define TARGET_SEAT_INTERFACE 5U
43 #define TARGET_XDG_VERSION 5U
46 static const char* event_names[] = {
47 "new seat",
"removed seat",
"new output",
"configure",
"pointer enter",
48 "pointer leave",
"pointer motion",
"pointer buttons",
"pointer axis",
"keyboard enter",
49 "key",
"touch frame begin",
"touch up",
"touch down",
"touch motion",
50 "touch cancel",
"touch frame end",
"frame done",
"close", NULL
54 static bool uwac_default_error_handler(UwacDisplay* display, UwacReturnCode code,
const char* msg,
59 (void)vfprintf(stderr,
"%s", args);
64 UwacErrorHandler uwacErrorHandler = uwac_default_error_handler;
66 void UwacInstallErrorHandler(UwacErrorHandler handler)
69 uwacErrorHandler = handler;
71 uwacErrorHandler = uwac_default_error_handler;
74 static void cb_shm_format(
void* data,
struct wl_shm* wl_shm, uint32_t format)
76 UwacDisplay* d = data;
78 if (format == WL_SHM_FORMAT_RGB565)
83 xrealloc((
void*)d->shm_formats,
sizeof(
enum wl_shm_format) * d->shm_formats_nb);
84 d->shm_formats[d->shm_formats_nb - 1] = format;
87 static struct wl_shm_listener shm_listener = { cb_shm_format };
89 static void xdg_shell_ping(
void* data,
struct xdg_wm_base* xdg_wm_base, uint32_t serial)
91 xdg_wm_base_pong(xdg_wm_base, serial);
94 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
98 #ifdef BUILD_FULLSCREEN_SHELL
99 static void fullscreen_capability(
void* data,
100 struct zwp_fullscreen_shell_v1* zwp_fullscreen_shell_v1,
105 static const struct zwp_fullscreen_shell_v1_listener fullscreen_shell_listener = {
106 fullscreen_capability,
110 static void display_destroy_seat(UwacDisplay* d, uint32_t name)
112 UwacSeat* seat = NULL;
113 UwacSeat* tmp = NULL;
114 wl_list_for_each_safe(seat, tmp, &d->seats, link)
116 if (seat->seat_id == name)
118 UwacSeatDestroy(seat);
123 static void UwacSeatRegisterDDM(UwacSeat* seat)
125 UwacDisplay* d = seat->display;
126 if (!d->data_device_manager)
129 if (!seat->data_device)
131 wl_data_device_manager_get_data_device(d->data_device_manager, seat->seat);
134 static void UwacRegisterCursor(UwacSeat* seat)
136 if (!seat || !seat->display || !seat->display->compositor)
139 seat->pointer_surface = wl_compositor_create_surface(seat->display->compositor);
142 static void registry_handle_global(
void* data,
struct wl_registry* registry, uint32_t
id,
143 const char* interface, uint32_t version)
145 UwacDisplay* d = data;
146 UwacGlobal* global = NULL;
147 global = xzalloc(
sizeof *global);
149 global->interface = xstrdup(interface);
150 global->version = version;
151 wl_list_insert(d->globals.prev, &global->link);
153 if (strcmp(interface,
"wl_compositor") == 0)
155 d->compositor = wl_registry_bind(registry,
id, &wl_compositor_interface,
156 min(TARGET_COMPOSITOR_INTERFACE, version));
158 else if (strcmp(interface,
"wl_shm") == 0)
161 wl_registry_bind(registry,
id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version));
162 wl_shm_add_listener(d->shm, &shm_listener, d);
164 else if (strcmp(interface,
"wl_output") == 0)
166 UwacOutput* output = NULL;
167 UwacOutputNewEvent* ev = NULL;
168 output = UwacCreateOutput(d,
id, version);
172 assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY,
"unable to create output\n"));
176 ev = (UwacOutputNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_OUTPUT);
181 else if (strcmp(interface,
"wl_seat") == 0)
183 UwacSeatNewEvent* ev = NULL;
184 UwacSeat* seat = NULL;
185 seat = UwacSeatNew(d,
id, min(version, TARGET_SEAT_INTERFACE));
189 assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY,
"unable to create new seat\n"));
193 UwacSeatRegisterDDM(seat);
194 UwacSeatRegisterClipboard(seat);
195 UwacRegisterCursor(seat);
196 ev = (UwacSeatNewEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT);
200 assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY,
"unable to create new seat event\n"));
206 else if (strcmp(interface,
"wl_data_device_manager") == 0)
208 UwacSeat* seat = NULL;
209 UwacSeat* tmp = NULL;
211 d->data_device_manager = wl_registry_bind(registry,
id, &wl_data_device_manager_interface,
212 min(TARGET_DDM_INTERFACE, version));
214 wl_list_for_each_safe(seat, tmp, &d->seats, link)
216 UwacSeatRegisterDDM(seat);
217 UwacSeatRegisterClipboard(seat);
218 UwacRegisterCursor(seat);
221 else if (strcmp(interface,
"wl_shell") == 0)
223 d->shell = wl_registry_bind(registry,
id, &wl_shell_interface,
224 min(TARGET_SHELL_INTERFACE, version));
226 else if (strcmp(interface,
"xdg_wm_base") == 0)
228 d->xdg_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1);
229 xdg_wm_base_add_listener(d->xdg_base, &xdg_wm_base_listener, d);
231 else if (strcmp(interface,
"wp_viewporter") == 0)
233 d->viewporter = wl_registry_bind(registry,
id, &wp_viewporter_interface, 1);
235 else if (strcmp(interface,
"zwp_keyboard_shortcuts_inhibit_manager_v1") == 0)
237 d->keyboard_inhibit_manager =
238 wl_registry_bind(registry,
id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1);
240 else if (strcmp(interface,
"zxdg_decoration_manager_v1") == 0)
242 d->deco_manager = wl_registry_bind(registry,
id, &zxdg_decoration_manager_v1_interface, 1);
244 else if (strcmp(interface,
"org_kde_kwin_server_decoration_manager") == 0)
246 d->kde_deco_manager =
247 wl_registry_bind(registry,
id, &org_kde_kwin_server_decoration_manager_interface, 1);
250 else if (strcmp(interface,
"ivi_application") == 0)
252 d->ivi_application = wl_registry_bind(registry,
id, &ivi_application_interface, 1);
255 #if BUILD_FULLSCREEN_SHELL
256 else if (strcmp(interface,
"zwp_fullscreen_shell_v1") == 0)
258 d->fullscreen_shell = wl_registry_bind(registry,
id, &zwp_fullscreen_shell_v1_interface, 1);
259 zwp_fullscreen_shell_v1_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d);
263 else if (strcmp(interface,
"text_cursor_position") == 0)
265 d->text_cursor_position = wl_registry_bind(registry,
id, &text_cursor_position_interface, 1);
267 else if (strcmp(interface,
"workspace_manager") == 0)
271 else if (strcmp(interface,
"wl_subcompositor") == 0)
273 d->subcompositor = wl_registry_bind(registry,
id, &wl_subcompositor_interface, 1);
277 static void registry_handle_global_remove(
void* data,
struct wl_registry* registry, uint32_t name)
279 UwacDisplay* d = data;
280 UwacGlobal* global = NULL;
281 UwacGlobal* tmp = NULL;
282 wl_list_for_each_safe(global, tmp, &d->globals, link)
284 if (global->name != name)
289 if (strcmp(global->interface,
"wl_output") == 0)
290 display_destroy_output(d, name);
294 if (strcmp(global->interface,
"wl_seat") == 0)
296 UwacSeatRemovedEvent* ev = NULL;
297 display_destroy_seat(d, name);
298 ev = (UwacSeatRemovedEvent*)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT);
304 wl_list_remove(&global->link);
305 free(global->interface);
310 static void UwacDestroyGlobal(UwacGlobal* global)
312 free(global->interface);
313 wl_list_remove(&global->link);
317 static void* display_bind(UwacDisplay* display, uint32_t name,
const struct wl_interface* interface,
320 return wl_registry_bind(display->registry, name, interface, version);
323 static const struct wl_registry_listener registry_listener = { registry_handle_global,
324 registry_handle_global_remove };
326 int UwacDisplayWatchFd(UwacDisplay* display,
int fd, uint32_t events, UwacTask* task)
328 struct epoll_event ep;
331 return epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
334 static void UwacDisplayUnwatchFd(UwacDisplay* display,
int fd)
336 epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
339 static void display_exit(UwacDisplay* display)
341 display->running =
false;
344 static void display_dispatch_events(UwacTask* task, uint32_t events)
346 UwacDisplay* display = container_of(task, UwacDisplay, dispatch_fd_task);
347 struct epoll_event ep;
349 display->display_fd_events = events;
351 if ((events & EPOLLERR) || (events & EPOLLHUP))
353 display_exit(display);
357 if (events & EPOLLIN)
359 ret = wl_display_dispatch(display->display);
363 display_exit(display);
368 if (events & EPOLLOUT)
370 ret = wl_display_flush(display->display);
374 ep.events = EPOLLIN | EPOLLERR | EPOLLHUP;
375 ep.data.ptr = &display->dispatch_fd_task;
376 epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep);
378 else if (ret == -1 && errno != EAGAIN)
380 display_exit(display);
386 UwacDisplay* UwacOpenDisplay(
const char* name, UwacReturnCode* err)
388 UwacDisplay* ret = NULL;
389 ret = (UwacDisplay*)xzalloc(
sizeof(*ret));
393 *err = UWAC_ERROR_NOMEMORY;
397 wl_list_init(&ret->globals);
398 wl_list_init(&ret->seats);
399 wl_list_init(&ret->outputs);
400 wl_list_init(&ret->windows);
401 ret->display = wl_display_connect(name);
403 if (ret->display == NULL)
405 char buffer[256] = { 0 };
406 (void)fprintf(stderr,
"failed to connect to Wayland display %s: %s\n", name,
407 uwac_strerror(errno, buffer,
sizeof(buffer)));
408 *err = UWAC_ERROR_UNABLE_TO_CONNECT;
412 ret->epoll_fd = uwac_os_epoll_create_cloexec();
414 if (ret->epoll_fd < 0)
416 *err = UWAC_NOT_ENOUGH_RESOURCES;
420 ret->display_fd = wl_display_get_fd(ret->display);
421 ret->registry = wl_display_get_registry(ret->display);
425 *err = UWAC_ERROR_NOMEMORY;
426 goto out_close_epoll;
429 wl_registry_add_listener(ret->registry, ®istry_listener, ret);
431 if ((wl_display_roundtrip(ret->display) < 0) || (wl_display_roundtrip(ret->display) < 0))
433 uwacErrorHandler(ret, UWAC_ERROR_UNABLE_TO_CONNECT,
434 "Failed to process Wayland connection: %m\n");
435 *err = UWAC_ERROR_UNABLE_TO_CONNECT;
436 goto out_free_registry;
439 ret->dispatch_fd_task.run = display_dispatch_events;
441 if (UwacDisplayWatchFd(ret, ret->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP,
442 &ret->dispatch_fd_task) < 0)
444 uwacErrorHandler(ret, UWAC_ERROR_INTERNAL,
"unable to watch display fd: %m\n");
445 *err = UWAC_ERROR_INTERNAL;
446 goto out_free_registry;
450 ret->last_error = *err = UWAC_SUCCESS;
453 wl_registry_destroy(ret->registry);
455 close(ret->epoll_fd);
457 wl_display_disconnect(ret->display);
463 int UwacDisplayDispatch(UwacDisplay* display,
int timeout)
467 UwacTask* task = NULL;
468 struct epoll_event ep[16];
469 wl_display_dispatch_pending(display->display);
471 if (!display->running)
474 ret = wl_display_flush(display->display);
476 if (ret < 0 && errno == EAGAIN)
478 ep[0].events = (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP);
479 ep[0].data.ptr = &display->dispatch_fd_task;
480 epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep[0]);
487 count = epoll_wait(display->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
489 for (
int i = 0; i < count; i++)
491 task = ep[i].data.ptr;
492 task->run(task, ep[i].events);
498 UwacReturnCode UwacDisplayGetLastError(
const UwacDisplay* display)
500 return display->last_error;
503 UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay)
505 UwacDisplay* display = NULL;
506 UwacSeat* seat = NULL;
507 UwacSeat* tmpSeat = NULL;
508 UwacWindow* window = NULL;
509 UwacWindow* tmpWindow = NULL;
510 UwacOutput* output = NULL;
511 UwacOutput* tmpOutput = NULL;
512 UwacGlobal* global = NULL;
513 UwacGlobal* tmpGlobal = NULL;
518 return UWAC_ERROR_INVALID_DISPLAY;
521 wl_list_for_each_safe(window, tmpWindow, &display->windows, link)
523 UwacDestroyWindow(&window);
526 wl_list_for_each_safe(seat, tmpSeat, &display->seats, link)
528 UwacSeatDestroy(seat);
531 wl_list_for_each_safe(output, tmpOutput, &display->outputs, link)
533 UwacDestroyOutput(output);
536 wl_list_for_each_safe(global, tmpGlobal, &display->globals, link)
538 UwacDestroyGlobal(global);
541 if (display->compositor)
542 wl_compositor_destroy(display->compositor);
544 if (display->keyboard_inhibit_manager)
545 zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(display->keyboard_inhibit_manager);
547 if (display->deco_manager)
548 zxdg_decoration_manager_v1_destroy(display->deco_manager);
550 if (display->kde_deco_manager)
551 org_kde_kwin_server_decoration_manager_destroy(display->kde_deco_manager);
553 #ifdef BUILD_FULLSCREEN_SHELL
555 if (display->fullscreen_shell)
556 zwp_fullscreen_shell_v1_destroy(display->fullscreen_shell);
561 if (display->ivi_application)
562 ivi_application_destroy(display->ivi_application);
566 if (display->xdg_toplevel)
567 xdg_toplevel_destroy(display->xdg_toplevel);
569 if (display->xdg_base)
570 xdg_wm_base_destroy(display->xdg_base);
573 wl_shell_destroy(display->shell);
576 wl_shm_destroy(display->shm);
578 if (display->viewporter)
579 wp_viewporter_destroy(display->viewporter);
581 if (display->subcompositor)
582 wl_subcompositor_destroy(display->subcompositor);
584 if (display->data_device_manager)
585 wl_data_device_manager_destroy(display->data_device_manager);
587 free(display->shm_formats);
588 wl_registry_destroy(display->registry);
589 close(display->epoll_fd);
590 wl_display_disconnect(display->display);
593 while (display->push_queue)
595 UwacEventListItem* item = display->push_queue;
596 display->push_queue = item->tail;
605 int UwacDisplayGetFd(UwacDisplay* display)
607 return display->epoll_fd;
610 static const char* errorStrings[] = {
612 "out of memory error",
613 "unable to connect to wayland display",
614 "invalid UWAC display",
615 "not enough resources",
623 const char* UwacErrorString(UwacReturnCode error)
625 if (error < UWAC_SUCCESS || error >= UWAC_ERROR_LAST)
626 return "invalid error code";
628 return errorStrings[error];
631 UwacReturnCode UwacDisplayQueryInterfaceVersion(
const UwacDisplay* display,
const char* name,
634 const UwacGlobal* global = NULL;
635 const UwacGlobal* tmp = NULL;
638 return UWAC_ERROR_INVALID_DISPLAY;
640 wl_list_for_each_safe(global, tmp, &display->globals, link)
642 if (strcmp(global->interface, name) == 0)
645 *version = global->version;
650 return UWAC_NOT_FOUND;
653 uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display)
662 display->last_error = UWAC_NOT_FOUND;
666 display->last_error = UWAC_SUCCESS;
667 return display->shm_formats_nb;
670 UwacReturnCode UwacDisplayQueryShmFormats(
const UwacDisplay* display,
enum wl_shm_format* formats,
671 int formats_size,
int* filled)
674 return UWAC_ERROR_INVALID_DISPLAY;
676 *filled = min((int64_t)display->shm_formats_nb, formats_size);
677 memcpy(formats, (
const void*)display->shm_formats, *filled *
sizeof(
enum wl_shm_format));
681 uint32_t UwacDisplayGetNbOutputs(
const UwacDisplay* display)
683 return wl_list_length(&display->outputs);
686 const UwacOutput* UwacDisplayGetOutput(UwacDisplay* display,
int index)
689 int display_count = 0;
690 UwacOutput* ret = NULL;
695 display_count = wl_list_length(&display->outputs);
696 if (display_count <= index)
699 wl_list_for_each(ret, &display->outputs, link)
708 display->last_error = UWAC_NOT_FOUND;
712 display->last_error = UWAC_SUCCESS;
716 UwacReturnCode UwacOutputGetResolution(
const UwacOutput* output, UwacSize* resolution)
718 if ((output->resolution.height <= 0) || (output->resolution.width <= 0))
719 return UWAC_ERROR_INTERNAL;
721 *resolution = output->resolution;
725 UwacReturnCode UwacOutputGetPosition(
const UwacOutput* output, UwacPosition* pos)
727 *pos = output->position;
731 UwacEvent* UwacDisplayNewEvent(UwacDisplay* display,
int type)
733 UwacEventListItem* ret = NULL;
740 ret = xzalloc(
sizeof(UwacEventListItem));
744 assert(uwacErrorHandler(display, UWAC_ERROR_NOMEMORY,
"unable to allocate a '%s' event",
746 display->last_error = UWAC_ERROR_NOMEMORY;
750 ret->event.type = type;
751 ret->tail = display->push_queue;
754 ret->tail->head = ret;
756 display->pop_queue = ret;
758 display->push_queue = ret;
762 bool UwacHasEvent(UwacDisplay* display)
764 return display->pop_queue != NULL;
767 UwacReturnCode UwacNextEvent(UwacDisplay* display, UwacEvent* event)
769 UwacEventListItem* prevItem = NULL;
773 return UWAC_ERROR_INVALID_DISPLAY;
775 while (!display->pop_queue)
777 ret = UwacDisplayDispatch(display, 1 * 1000);
780 return UWAC_ERROR_INTERNAL;
782 return UWAC_ERROR_CLOSED;
785 prevItem = display->pop_queue->head;
786 *
event = display->pop_queue->event;
787 free(display->pop_queue);
788 display->pop_queue = prevItem;
791 prevItem->tail = NULL;
793 display->push_queue = NULL;