23#include "uwac-utils.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  
   46static 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
 
   54static bool uwac_default_error_handler(UwacDisplay* display, UwacReturnCode code, 
const char* msg,
 
   59  (void)vfprintf(stderr, 
"%s", args);
 
   64UwacErrorHandler uwacErrorHandler = uwac_default_error_handler;
 
   66void UwacInstallErrorHandler(UwacErrorHandler handler)
 
   69    uwacErrorHandler = handler;
 
   71    uwacErrorHandler = uwac_default_error_handler;
 
   74static 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;
 
   87static struct wl_shm_listener shm_listener = { cb_shm_format };
 
   89static 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);
 
   94static const struct xdg_wm_base_listener xdg_wm_base_listener = {
 
   98#ifdef BUILD_FULLSCREEN_SHELL 
   99static void fullscreen_capability(
void* data,
 
  100                                  struct zwp_fullscreen_shell_v1* zwp_fullscreen_shell_v1,
 
  105static const struct zwp_fullscreen_shell_v1_listener fullscreen_shell_listener = {
 
  106  fullscreen_capability,
 
  110static 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);
 
  123static 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);
 
  134static void UwacRegisterCursor(UwacSeat* seat)
 
  136  if (!seat || !seat->display || !seat->display->compositor)
 
  139  seat->pointer_surface = wl_compositor_create_surface(seat->display->compositor);
 
  142static 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);
 
  277static 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);
 
  310static void UwacDestroyGlobal(UwacGlobal* global)
 
  312  free(global->interface);
 
  313  wl_list_remove(&global->link);
 
  317static void* display_bind(UwacDisplay* display, uint32_t name, 
const struct wl_interface* interface,
 
  320  return wl_registry_bind(display->registry, name, interface, version);
 
  323static const struct wl_registry_listener registry_listener = { registry_handle_global,
 
  324                                                             registry_handle_global_remove };
 
  326int 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);
 
  334static void UwacDisplayUnwatchFd(UwacDisplay* display, 
int fd)
 
  336  epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
 
  339static void display_exit(UwacDisplay* display)
 
  341  display->running = 
false;
 
  344static 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);
 
  386UwacDisplay* 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);
 
  463int 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);
 
  498UwacReturnCode UwacDisplayGetLastError(
const UwacDisplay* display)
 
  500  return display->last_error;
 
  503UwacReturnCode 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;
 
  605int UwacDisplayGetFd(UwacDisplay* display)
 
  607  return display->epoll_fd;
 
  610static const char* errorStrings[] = {
 
  612  "out of memory error",
 
  613  "unable to connect to wayland display",
 
  614  "invalid UWAC display",
 
  615  "not enough resources",
 
  623const char* UwacErrorString(UwacReturnCode error)
 
  625  if (error < UWAC_SUCCESS || error >= UWAC_ERROR_LAST)
 
  626    return "invalid error code";
 
  628  return errorStrings[error];
 
  631UwacReturnCode 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;
 
  653uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay* display)
 
  662    display->last_error = UWAC_NOT_FOUND;
 
  666  display->last_error = UWAC_SUCCESS;
 
  667  return display->shm_formats_nb;
 
  670UwacReturnCode 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));
 
  681uint32_t UwacDisplayGetNbOutputs(
const UwacDisplay* display)
 
  683  return wl_list_length(&display->outputs);
 
  686const 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;
 
  716UwacReturnCode 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;
 
  725UwacReturnCode UwacOutputGetPosition(
const UwacOutput* output, UwacPosition* pos)
 
  727  *pos = output->position;
 
  731UwacEvent* 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;
 
  762bool UwacHasEvent(UwacDisplay* display)
 
  764  return display->pop_queue != NULL;
 
  767UwacReturnCode 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;