src/video/wayland/SDL_waylandevents.c
author Alex Szpakowski <slime73@gmail.com>
Sat, 10 Nov 2018 16:15:48 -0400
changeset 12404 eb60e952b13f
parent 12342 7cec5c0510ae
child 12455 bc838d7a29dc
permissions -rw-r--r--
Add SDL_TouchDeviceType enum and SDL_GetTouchDeviceType(SDL_TouchID id).

Touch device types include SDL_TOUCH_DEVICE_DIRECT (a touch screen with window-relative coordinates for touches), SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE (a trackpad-style device with absolute device coordinates), and SDL_TOUCH_DEVICE_INDIRECT_RELATIVE (a trackpad-style device with screen cursor-relative coordinates).

Phone screens are an example of a direct device type. Mac trackpads are the indirect-absolute touch device type. The Apple TV remote is an indirect-relative touch device type.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 #include "../../SDL_internal.h"
    23 
    24 #if SDL_VIDEO_DRIVER_WAYLAND
    25 
    26 #include "SDL_stdinc.h"
    27 #include "SDL_assert.h"
    28 #include "SDL_log.h"
    29 
    30 #include "../../core/unix/SDL_poll.h"
    31 #include "../../events/SDL_sysevents.h"
    32 #include "../../events/SDL_events_c.h"
    33 #include "../../events/scancodes_xfree86.h"
    34 
    35 #include "SDL_waylandvideo.h"
    36 #include "SDL_waylandevents_c.h"
    37 #include "SDL_waylandwindow.h"
    38 
    39 #include "SDL_waylanddyn.h"
    40 
    41 #include "pointer-constraints-unstable-v1-client-protocol.h"
    42 #include "relative-pointer-unstable-v1-client-protocol.h"
    43 #include "xdg-shell-client-protocol.h"
    44 #include "xdg-shell-unstable-v6-client-protocol.h"
    45 
    46 #include <linux/input.h>
    47 #include <sys/select.h>
    48 #include <sys/mman.h>
    49 #include <poll.h>
    50 #include <unistd.h>
    51 #include <xkbcommon/xkbcommon.h>
    52 
    53 struct SDL_WaylandInput {
    54     SDL_VideoData *display;
    55     struct wl_seat *seat;
    56     struct wl_pointer *pointer;
    57     struct wl_touch *touch;
    58     struct wl_keyboard *keyboard;
    59     SDL_WaylandDataDevice *data_device;
    60     struct zwp_relative_pointer_v1 *relative_pointer;
    61     SDL_WindowData *pointer_focus;
    62     SDL_WindowData *keyboard_focus;
    63 
    64     /* Last motion location */
    65     wl_fixed_t sx_w;
    66     wl_fixed_t sy_w;
    67 
    68     double dx_frac;
    69     double dy_frac;
    70 
    71     struct {
    72         struct xkb_keymap *keymap;
    73         struct xkb_state *state;
    74     } xkb;
    75 };
    76 
    77 struct SDL_WaylandTouchPoint {
    78     SDL_TouchID id;
    79     float x;
    80     float y;
    81     struct wl_surface* surface;
    82 
    83     struct SDL_WaylandTouchPoint* prev;
    84     struct SDL_WaylandTouchPoint* next;
    85 };
    86 
    87 struct SDL_WaylandTouchPointList {
    88     struct SDL_WaylandTouchPoint* head;
    89     struct SDL_WaylandTouchPoint* tail;
    90 };
    91 
    92 static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
    93 
    94 static void
    95 touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
    96 {
    97     struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
    98 
    99     tp->id = id;
   100     tp->x = x;
   101     tp->y = y;
   102     tp->surface = surface;
   103 
   104     if (touch_points.tail) {
   105         touch_points.tail->next = tp;
   106         tp->prev = touch_points.tail;
   107     } else {
   108         touch_points.head = tp;
   109         tp->prev = NULL;
   110     }
   111 
   112     touch_points.tail = tp;
   113     tp->next = NULL;
   114 }
   115 
   116 static void
   117 touch_update(SDL_TouchID id, float x, float y)
   118 {
   119     struct SDL_WaylandTouchPoint* tp = touch_points.head;
   120 
   121     while (tp) {
   122         if (tp->id == id) {
   123             tp->x = x;
   124             tp->y = y;
   125         }
   126 
   127         tp = tp->next;
   128     }
   129 }
   130 
   131 static void
   132 touch_del(SDL_TouchID id, float* x, float* y)
   133 {
   134     struct SDL_WaylandTouchPoint* tp = touch_points.head;
   135 
   136     while (tp) {
   137         if (tp->id == id) {
   138             *x = tp->x;
   139             *y = tp->y;
   140 
   141             if (tp->prev) {
   142                 tp->prev->next = tp->next;
   143             } else {
   144                 touch_points.head = tp->next;
   145             }
   146 
   147             if (tp->next) {
   148                 tp->next->prev = tp->prev;
   149             } else {
   150                 touch_points.tail = tp->prev;
   151             }
   152 
   153             SDL_free(tp);
   154         }
   155 
   156         tp = tp->next;
   157     }
   158 }
   159 
   160 static struct wl_surface*
   161 touch_surface(SDL_TouchID id)
   162 {
   163     struct SDL_WaylandTouchPoint* tp = touch_points.head;
   164 
   165     while (tp) {
   166         if (tp->id == id) {
   167             return tp->surface;
   168         }
   169 
   170         tp = tp->next;
   171     }
   172 
   173     return NULL;
   174 }
   175 
   176 void
   177 Wayland_PumpEvents(_THIS)
   178 {
   179     SDL_VideoData *d = _this->driverdata;
   180 
   181     WAYLAND_wl_display_flush(d->display);
   182 
   183     if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
   184         WAYLAND_wl_display_dispatch(d->display);
   185     }
   186     else
   187     {
   188         WAYLAND_wl_display_dispatch_pending(d->display);
   189     }
   190 }
   191 
   192 static void
   193 pointer_handle_enter(void *data, struct wl_pointer *pointer,
   194                      uint32_t serial, struct wl_surface *surface,
   195                      wl_fixed_t sx_w, wl_fixed_t sy_w)
   196 {
   197     struct SDL_WaylandInput *input = data;
   198     SDL_WindowData *window;
   199 
   200     if (!surface) {
   201         /* enter event for a window we've just destroyed */
   202         return;
   203     }
   204 
   205     /* This handler will be called twice in Wayland 1.4
   206      * Once for the window surface which has valid user data
   207      * and again for the mouse cursor surface which does not have valid user data
   208      * We ignore the later
   209      */
   210 
   211     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
   212 
   213     if (window) {
   214         input->pointer_focus = window;
   215         SDL_SetMouseFocus(window->sdlwindow);
   216     }
   217 }
   218 
   219 static void
   220 pointer_handle_leave(void *data, struct wl_pointer *pointer,
   221                      uint32_t serial, struct wl_surface *surface)
   222 {
   223     struct SDL_WaylandInput *input = data;
   224 
   225     if (input->pointer_focus) {
   226         SDL_SetMouseFocus(NULL);
   227         input->pointer_focus = NULL;
   228     }
   229 }
   230 
   231 static void
   232 pointer_handle_motion(void *data, struct wl_pointer *pointer,
   233                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
   234 {
   235     struct SDL_WaylandInput *input = data;
   236     SDL_WindowData *window = input->pointer_focus;
   237     input->sx_w = sx_w;
   238     input->sy_w = sy_w;
   239     if (input->pointer_focus) {
   240         const int sx = wl_fixed_to_int(sx_w);
   241         const int sy = wl_fixed_to_int(sy_w);
   242         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
   243     }
   244 }
   245 
   246 static SDL_bool
   247 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
   248 {
   249     SDL_WindowData *window_data = input->pointer_focus;
   250     SDL_Window *window = window_data->sdlwindow;
   251 
   252     if (window->hit_test) {
   253         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
   254         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
   255 
   256         static const uint32_t directions_wl[] = {
   257             WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
   258             WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
   259             WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
   260             WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
   261         };
   262 
   263         /* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs
   264            WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */
   265         const uint32_t *directions_zxdg = directions_wl;
   266 
   267         switch (rc) {
   268             case SDL_HITTEST_DRAGGABLE:
   269                 if (input->display->shell.xdg) {
   270                     xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial);
   271                 } else if (input->display->shell.zxdg) {
   272                     zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial);
   273                 } else {
   274                     wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial);
   275                 }
   276                 return SDL_TRUE;
   277 
   278             case SDL_HITTEST_RESIZE_TOPLEFT:
   279             case SDL_HITTEST_RESIZE_TOP:
   280             case SDL_HITTEST_RESIZE_TOPRIGHT:
   281             case SDL_HITTEST_RESIZE_RIGHT:
   282             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
   283             case SDL_HITTEST_RESIZE_BOTTOM:
   284             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
   285             case SDL_HITTEST_RESIZE_LEFT:
   286                 if (input->display->shell.xdg) {
   287                     xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   288                 } else if (input->display->shell.zxdg) {
   289                     zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   290                 } else {
   291                     wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   292                 }
   293                 return SDL_TRUE;
   294 
   295             default: return SDL_FALSE;
   296         }
   297     }
   298 
   299     return SDL_FALSE;
   300 }
   301 
   302 static void
   303 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
   304                              uint32_t time, uint32_t button, uint32_t state_w)
   305 {
   306     SDL_WindowData *window = input->pointer_focus;
   307     enum wl_pointer_button_state state = state_w;
   308     uint32_t sdl_button;
   309 
   310     if  (input->pointer_focus) {
   311         switch (button) {
   312             case BTN_LEFT:
   313                 sdl_button = SDL_BUTTON_LEFT;
   314                 if (ProcessHitTest(input, serial)) {
   315                     return;  /* don't pass this event on to app. */
   316                 }
   317                 break;
   318             case BTN_MIDDLE:
   319                 sdl_button = SDL_BUTTON_MIDDLE;
   320                 break;
   321             case BTN_RIGHT:
   322                 sdl_button = SDL_BUTTON_RIGHT;
   323                 break;
   324             case BTN_SIDE:
   325                 sdl_button = SDL_BUTTON_X1;
   326                 break;
   327             case BTN_EXTRA:
   328                 sdl_button = SDL_BUTTON_X2;
   329                 break;
   330             default:
   331                 return;
   332         }
   333             
   334         Wayland_data_device_set_serial(input->data_device, serial); 
   335 
   336         SDL_SendMouseButton(window->sdlwindow, 0,
   337                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   338     }
   339 }
   340 
   341 static void
   342 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
   343                       uint32_t time, uint32_t button, uint32_t state_w)
   344 {
   345     struct SDL_WaylandInput *input = data;
   346 
   347     pointer_handle_button_common(input, serial, time, button, state_w);
   348 }
   349 
   350 static void
   351 pointer_handle_axis_common(struct SDL_WaylandInput *input,
   352                            uint32_t time, uint32_t axis, wl_fixed_t value)
   353 {
   354     SDL_WindowData *window = input->pointer_focus;
   355     enum wl_pointer_axis a = axis;
   356     float x, y;
   357 
   358     if (input->pointer_focus) {
   359         switch (a) {
   360             case WL_POINTER_AXIS_VERTICAL_SCROLL:
   361                 x = 0;
   362                 y = 0 - (float)wl_fixed_to_double(value);
   363                 break;
   364             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
   365                 x = 0 - (float)wl_fixed_to_double(value);
   366                 y = 0;
   367                 break;
   368             default:
   369                 return;
   370         }
   371 
   372         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
   373     }
   374 }
   375 
   376 static void
   377 pointer_handle_axis(void *data, struct wl_pointer *pointer,
   378                     uint32_t time, uint32_t axis, wl_fixed_t value)
   379 {
   380     struct SDL_WaylandInput *input = data;
   381 
   382     pointer_handle_axis_common(input, time, axis, value);
   383 }
   384 
   385 static const struct wl_pointer_listener pointer_listener = {
   386     pointer_handle_enter,
   387     pointer_handle_leave,
   388     pointer_handle_motion,
   389     pointer_handle_button,
   390     pointer_handle_axis,
   391     NULL, /* frame */
   392     NULL, /* axis_source */
   393     NULL, /* axis_stop */
   394     NULL, /* axis_discrete */
   395 };
   396 
   397 static void
   398 touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
   399                    unsigned int timestamp, struct wl_surface *surface,
   400                    int id, wl_fixed_t fx, wl_fixed_t fy)
   401 {
   402     float x, y;
   403     SDL_WindowData* window;
   404 
   405     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
   406 
   407     x = wl_fixed_to_double(fx) / window->sdlwindow->w;
   408     y = wl_fixed_to_double(fy) / window->sdlwindow->h;
   409 
   410     touch_add(id, x, y, surface);
   411     SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f);
   412 }
   413 
   414 static void
   415 touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
   416                  unsigned int timestamp, int id)
   417 {
   418     float x = 0, y = 0;
   419 
   420     touch_del(id, &x, &y);
   421     SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f);
   422 }
   423 
   424 static void
   425 touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
   426                      int id, wl_fixed_t fx, wl_fixed_t fy)
   427 {
   428     float x, y;
   429     SDL_WindowData* window;
   430 
   431     window = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
   432 
   433     x = wl_fixed_to_double(fx) / window->sdlwindow->w;
   434     y = wl_fixed_to_double(fy) / window->sdlwindow->h;
   435 
   436     touch_update(id, x, y);
   437     SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f);
   438 }
   439 
   440 static void
   441 touch_handler_frame(void *data, struct wl_touch *touch)
   442 {
   443 
   444 }
   445 
   446 static void
   447 touch_handler_cancel(void *data, struct wl_touch *touch)
   448 {
   449 
   450 }
   451 
   452 static const struct wl_touch_listener touch_listener = {
   453     touch_handler_down,
   454     touch_handler_up,
   455     touch_handler_motion,
   456     touch_handler_frame,
   457     touch_handler_cancel,
   458     NULL, /* shape */
   459     NULL, /* orientation */
   460 };
   461 
   462 static void
   463 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
   464                        uint32_t format, int fd, uint32_t size)
   465 {
   466     struct SDL_WaylandInput *input = data;
   467     char *map_str;
   468 
   469     if (!data) {
   470         close(fd);
   471         return;
   472     }
   473 
   474     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
   475         close(fd);
   476         return;
   477     }
   478 
   479     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
   480     if (map_str == MAP_FAILED) {
   481         close(fd);
   482         return;
   483     }
   484 
   485     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
   486                                                 map_str,
   487                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
   488                                                 0);
   489     munmap(map_str, size);
   490     close(fd);
   491 
   492     if (!input->xkb.keymap) {
   493         fprintf(stderr, "failed to compile keymap\n");
   494         return;
   495     }
   496 
   497     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
   498     if (!input->xkb.state) {
   499         fprintf(stderr, "failed to create XKB state\n");
   500         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   501         input->xkb.keymap = NULL;
   502         return;
   503     }
   504 }
   505 
   506 static void
   507 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
   508                       uint32_t serial, struct wl_surface *surface,
   509                       struct wl_array *keys)
   510 {
   511     struct SDL_WaylandInput *input = data;
   512     SDL_WindowData *window;
   513 
   514     if (!surface) {
   515         /* enter event for a window we've just destroyed */
   516         return;
   517     }
   518 
   519     window = wl_surface_get_user_data(surface);
   520 
   521     if (window) {
   522         input->keyboard_focus = window;
   523         window->keyboard_device = input;
   524         SDL_SetKeyboardFocus(window->sdlwindow);
   525     }
   526 }
   527 
   528 static void
   529 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
   530                       uint32_t serial, struct wl_surface *surface)
   531 {
   532     SDL_SetKeyboardFocus(NULL);
   533 }
   534 
   535 static void
   536 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
   537                     uint32_t serial, uint32_t time, uint32_t key,
   538                     uint32_t state_w)
   539 {
   540     struct SDL_WaylandInput *input = data;
   541     SDL_WindowData *window = input->keyboard_focus;
   542     enum wl_keyboard_key_state state = state_w;
   543     const xkb_keysym_t *syms;
   544     uint32_t scancode;
   545     char text[8];
   546     int size;
   547 
   548     if (key < SDL_arraysize(xfree86_scancode_table2)) {
   549         scancode = xfree86_scancode_table2[key];
   550 
   551         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
   552         if (scancode != SDL_SCANCODE_UNKNOWN)
   553             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
   554                                 SDL_PRESSED : SDL_RELEASED, scancode);
   555     }
   556 
   557     if (!window || window->keyboard_device != input || !input->xkb.state)
   558         return;
   559 
   560     // TODO can this happen?
   561     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
   562         return;
   563 
   564     if (state) {
   565         size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
   566 
   567         if (size > 0) {
   568             text[size] = 0;
   569 
   570             Wayland_data_device_set_serial(input->data_device, serial);
   571 
   572             SDL_SendKeyboardText(text);
   573         }
   574     }
   575 }
   576 
   577 static void
   578 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
   579                           uint32_t serial, uint32_t mods_depressed,
   580                           uint32_t mods_latched, uint32_t mods_locked,
   581                           uint32_t group)
   582 {
   583     struct SDL_WaylandInput *input = data;
   584 
   585     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
   586                           mods_locked, 0, 0, group);
   587 }
   588 
   589 static const struct wl_keyboard_listener keyboard_listener = {
   590     keyboard_handle_keymap,
   591     keyboard_handle_enter,
   592     keyboard_handle_leave,
   593     keyboard_handle_key,
   594     keyboard_handle_modifiers,
   595     NULL, /* repeat_info */
   596 };
   597 
   598 static void
   599 seat_handle_capabilities(void *data, struct wl_seat *seat,
   600                          enum wl_seat_capability caps)
   601 {
   602     struct SDL_WaylandInput *input = data;
   603 
   604     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
   605         input->pointer = wl_seat_get_pointer(seat);
   606         input->display->pointer = input->pointer;
   607         wl_pointer_set_user_data(input->pointer, input);
   608         wl_pointer_add_listener(input->pointer, &pointer_listener,
   609                                 input);
   610     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
   611         wl_pointer_destroy(input->pointer);
   612         input->pointer = NULL;
   613         input->display->pointer = NULL;
   614     }
   615 
   616     if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
   617         SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
   618         input->touch = wl_seat_get_touch(seat);
   619         wl_touch_set_user_data(input->touch, input);
   620         wl_touch_add_listener(input->touch, &touch_listener,
   621                                  input);
   622     } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
   623         SDL_DelTouch(1);
   624         wl_touch_destroy(input->touch);
   625         input->touch = NULL;
   626     }
   627 
   628     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
   629         input->keyboard = wl_seat_get_keyboard(seat);
   630         wl_keyboard_set_user_data(input->keyboard, input);
   631         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
   632                                  input);
   633     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
   634         wl_keyboard_destroy(input->keyboard);
   635         input->keyboard = NULL;
   636     }
   637 }
   638 
   639 static const struct wl_seat_listener seat_listener = {
   640     seat_handle_capabilities,
   641     NULL, /* name */
   642 };
   643 
   644 static void
   645 data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
   646                           const char *mime_type)
   647 {
   648 }
   649 
   650 static void
   651 data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
   652                         const char *mime_type, int32_t fd)
   653 {
   654     Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
   655 }
   656                        
   657 static void
   658 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
   659 {
   660     Wayland_data_source_destroy(data);
   661 }
   662                        
   663 static void
   664 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
   665 {
   666 }
   667 
   668 static void
   669 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
   670 {
   671 }
   672 
   673 static void
   674 data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
   675                           uint32_t dnd_action)
   676 {
   677 }
   678 
   679 static const struct wl_data_source_listener data_source_listener = {
   680     data_source_handle_target,
   681     data_source_handle_send,
   682     data_source_handle_cancelled,
   683     data_source_handle_dnd_drop_performed, // Version 3
   684     data_source_handle_dnd_finished,       // Version 3
   685     data_source_handle_action,             // Version 3
   686 };
   687 
   688 SDL_WaylandDataSource*
   689 Wayland_data_source_create(_THIS)
   690 {
   691     SDL_WaylandDataSource *data_source = NULL;
   692     SDL_VideoData *driver_data = NULL;
   693     struct wl_data_source *id = NULL;
   694 
   695     if (_this == NULL || _this->driverdata == NULL) {
   696         SDL_SetError("Video driver uninitialized");
   697     } else {
   698         driver_data = _this->driverdata;
   699 
   700         if (driver_data->data_device_manager != NULL) {
   701             id = wl_data_device_manager_create_data_source(
   702                      driver_data->data_device_manager);
   703         }
   704 
   705         if (id == NULL) { 
   706             SDL_SetError("Wayland unable to create data source");
   707         } else {
   708             data_source = SDL_calloc(1, sizeof *data_source);
   709             if (data_source == NULL) {
   710                 SDL_OutOfMemory();
   711                 wl_data_source_destroy(id);
   712             } else {
   713                 WAYLAND_wl_list_init(&(data_source->mimes));
   714                 data_source->source = id;
   715                 wl_data_source_set_user_data(id, data_source);
   716                 wl_data_source_add_listener(id, &data_source_listener,
   717                                             data_source);
   718             }
   719         }
   720     }
   721     return data_source;
   722 }
   723 
   724 static void
   725 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
   726                         const char *mime_type)
   727 {
   728     SDL_WaylandDataOffer *offer = data;
   729     Wayland_data_offer_add_mime(offer, mime_type);
   730 }
   731 
   732 static void
   733 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
   734                                  uint32_t source_actions)
   735 {
   736 }
   737 
   738 static void
   739 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
   740                           uint32_t dnd_action)
   741 {
   742 }
   743 
   744 static const struct wl_data_offer_listener data_offer_listener = {
   745     data_offer_handle_offer,
   746     data_offer_handle_source_actions, // Version 3
   747     data_offer_handle_actions,        // Version 3
   748 };
   749 
   750 static void
   751 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
   752                               struct wl_data_offer *id)
   753 {
   754     SDL_WaylandDataOffer *data_offer = NULL;
   755 
   756     data_offer = SDL_calloc(1, sizeof *data_offer);
   757     if (data_offer == NULL) {
   758         SDL_OutOfMemory();
   759     } else {
   760         data_offer->offer = id;
   761         data_offer->data_device = data;
   762         WAYLAND_wl_list_init(&(data_offer->mimes));
   763         wl_data_offer_set_user_data(id, data_offer);
   764         wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
   765     }
   766 }
   767 
   768 static void
   769 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
   770                          uint32_t serial, struct wl_surface *surface,
   771                          wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
   772 {
   773     SDL_WaylandDataDevice *data_device = data;
   774     SDL_bool has_mime = SDL_FALSE;
   775     uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; 
   776         
   777     data_device->drag_serial = serial;
   778 
   779     if (id != NULL) {
   780         data_device->drag_offer = wl_data_offer_get_user_data(id);
   781 
   782         /* TODO: SDL Support more mime types */
   783         has_mime = Wayland_data_offer_has_mime(
   784             data_device->drag_offer, FILE_MIME);
   785 
   786         /* If drag_mime is NULL this will decline the offer */
   787         wl_data_offer_accept(id, serial,
   788                              (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
   789 
   790         /* SDL only supports "copy" style drag and drop */
   791         if (has_mime == SDL_TRUE) {
   792             dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
   793         }
   794         wl_data_offer_set_actions(data_device->drag_offer->offer,
   795                                   dnd_action, dnd_action);
   796     }
   797 }
   798 
   799 static void
   800 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
   801 {
   802     SDL_WaylandDataDevice *data_device = data;
   803     SDL_WaylandDataOffer *offer = NULL;
   804 
   805     if (data_device->selection_offer != NULL) {
   806         data_device->selection_offer = NULL;
   807         Wayland_data_offer_destroy(offer);
   808     }
   809 }
   810 
   811 static void
   812 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
   813                           uint32_t time, wl_fixed_t x, wl_fixed_t y)
   814 {
   815 }
   816 
   817 static void
   818 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
   819 {
   820     SDL_WaylandDataDevice *data_device = data;
   821     void *buffer = NULL;
   822     size_t length = 0;
   823 
   824     const char *current_uri = NULL;
   825     const char *last_char = NULL;
   826     char *current_char = NULL;
   827     
   828     if (data_device->drag_offer != NULL) {
   829         /* TODO: SDL Support more mime types */
   830         buffer = Wayland_data_offer_receive(data_device->drag_offer,
   831                                             &length, FILE_MIME, SDL_FALSE);
   832 
   833         /* uri-list */
   834         current_uri = (const char *)buffer;
   835         last_char = (const char *)buffer + length;
   836         for (current_char = buffer; current_char < last_char; ++current_char) {
   837             if (*current_char == '\n' || *current_char == 0) {
   838                 if (*current_uri != 0 && *current_uri != '#') {
   839                     *current_char = 0;
   840                     SDL_SendDropFile(NULL, current_uri);
   841                 }
   842                 current_uri = (const char *)current_char + 1;
   843             }
   844         }
   845 
   846         SDL_free(buffer);
   847     }
   848 }
   849 
   850 static void
   851 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
   852                              struct wl_data_offer *id)
   853 {    
   854     SDL_WaylandDataDevice *data_device = data;
   855     SDL_WaylandDataOffer *offer = NULL;
   856 
   857     if (id != NULL) {
   858         offer = wl_data_offer_get_user_data(id);
   859     }
   860 
   861     if (data_device->selection_offer != offer) {
   862         Wayland_data_offer_destroy(data_device->selection_offer);
   863         data_device->selection_offer = offer;
   864     }
   865 
   866     SDL_SendClipboardUpdate();
   867 }
   868 
   869 static const struct wl_data_device_listener data_device_listener = {
   870     data_device_handle_data_offer,
   871     data_device_handle_enter,
   872     data_device_handle_leave,
   873     data_device_handle_motion,
   874     data_device_handle_drop,
   875     data_device_handle_selection
   876 };
   877 
   878 void
   879 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
   880 {
   881     struct SDL_WaylandInput *input;
   882     SDL_WaylandDataDevice *data_device = NULL;
   883 
   884     input = SDL_calloc(1, sizeof *input);
   885     if (input == NULL)
   886         return;
   887 
   888     input->display = d;
   889     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
   890     input->sx_w = wl_fixed_from_int(0);
   891     input->sy_w = wl_fixed_from_int(0);
   892     d->input = input;
   893     
   894     if (d->data_device_manager != NULL) {
   895         data_device = SDL_calloc(1, sizeof *data_device);
   896         if (data_device == NULL) {
   897             return;
   898         }
   899 
   900         data_device->data_device = wl_data_device_manager_get_data_device(
   901             d->data_device_manager, input->seat
   902         );
   903         data_device->video_data = d;
   904 
   905         if (data_device->data_device == NULL) {
   906             SDL_free(data_device);
   907         } else {
   908             wl_data_device_set_user_data(data_device->data_device, data_device);
   909             wl_data_device_add_listener(data_device->data_device,
   910                                         &data_device_listener, data_device);
   911             input->data_device = data_device;
   912         }
   913     }
   914 
   915     wl_seat_add_listener(input->seat, &seat_listener, input);
   916     wl_seat_set_user_data(input->seat, input);
   917 
   918     WAYLAND_wl_display_flush(d->display);
   919 }
   920 
   921 void Wayland_display_destroy_input(SDL_VideoData *d)
   922 {
   923     struct SDL_WaylandInput *input = d->input;
   924 
   925     if (!input)
   926         return;
   927 
   928     if (input->data_device != NULL) {
   929         Wayland_data_device_clear_selection(input->data_device);
   930         if (input->data_device->selection_offer != NULL) {
   931             Wayland_data_offer_destroy(input->data_device->selection_offer);
   932         }
   933         if (input->data_device->drag_offer != NULL) {
   934             Wayland_data_offer_destroy(input->data_device->drag_offer);
   935         }
   936         if (input->data_device->data_device != NULL) {
   937             wl_data_device_release(input->data_device->data_device);
   938         }
   939         SDL_free(input->data_device);
   940     }
   941 
   942     if (input->keyboard)
   943         wl_keyboard_destroy(input->keyboard);
   944 
   945     if (input->pointer)
   946         wl_pointer_destroy(input->pointer);
   947 
   948     if (input->touch) {
   949         SDL_DelTouch(1);
   950         wl_touch_destroy(input->touch);
   951     }
   952 
   953     if (input->seat)
   954         wl_seat_destroy(input->seat);
   955 
   956     if (input->xkb.state)
   957         WAYLAND_xkb_state_unref(input->xkb.state);
   958 
   959     if (input->xkb.keymap)
   960         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   961 
   962     SDL_free(input);
   963     d->input = NULL;
   964 }
   965 
   966 SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
   967 {
   968     if (input == NULL) {
   969         return NULL;
   970     }
   971 
   972     return input->data_device;
   973 }
   974 
   975 /* !!! FIXME: just merge these into display_handle_global(). */
   976 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
   977 {
   978     d->relative_pointer_manager =
   979         wl_registry_bind(d->registry, id,
   980                          &zwp_relative_pointer_manager_v1_interface, 1);
   981 }
   982 
   983 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
   984 {
   985     if (d->relative_pointer_manager)
   986         zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
   987 }
   988 
   989 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
   990 {
   991     d->pointer_constraints =
   992         wl_registry_bind(d->registry, id,
   993                          &zwp_pointer_constraints_v1_interface, 1);
   994 }
   995 
   996 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
   997 {
   998     if (d->pointer_constraints)
   999         zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
  1000 }
  1001 
  1002 static void
  1003 relative_pointer_handle_relative_motion(void *data,
  1004                                         struct zwp_relative_pointer_v1 *pointer,
  1005                                         uint32_t time_hi,
  1006                                         uint32_t time_lo,
  1007                                         wl_fixed_t dx_w,
  1008                                         wl_fixed_t dy_w,
  1009                                         wl_fixed_t dx_unaccel_w,
  1010                                         wl_fixed_t dy_unaccel_w)
  1011 {
  1012     struct SDL_WaylandInput *input = data;
  1013     SDL_VideoData *d = input->display;
  1014     SDL_WindowData *window = input->pointer_focus;
  1015     double dx_unaccel;
  1016     double dy_unaccel;
  1017     double dx;
  1018     double dy;
  1019 
  1020     dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
  1021     dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
  1022 
  1023     /* Add left over fraction from last event. */
  1024     dx_unaccel += input->dx_frac;
  1025     dy_unaccel += input->dy_frac;
  1026 
  1027     input->dx_frac = modf(dx_unaccel, &dx);
  1028     input->dy_frac = modf(dy_unaccel, &dy);
  1029 
  1030     if (input->pointer_focus && d->relative_mouse_mode) {
  1031         SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
  1032     }
  1033 }
  1034 
  1035 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
  1036     relative_pointer_handle_relative_motion,
  1037 };
  1038 
  1039 static void
  1040 locked_pointer_locked(void *data,
  1041                       struct zwp_locked_pointer_v1 *locked_pointer)
  1042 {
  1043 }
  1044 
  1045 static void
  1046 locked_pointer_unlocked(void *data,
  1047                         struct zwp_locked_pointer_v1 *locked_pointer)
  1048 {
  1049 }
  1050 
  1051 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
  1052     locked_pointer_locked,
  1053     locked_pointer_unlocked,
  1054 };
  1055 
  1056 static void
  1057 lock_pointer_to_window(SDL_Window *window,
  1058                        struct SDL_WaylandInput *input)
  1059 {
  1060     SDL_WindowData *w = window->driverdata;
  1061     SDL_VideoData *d = input->display;
  1062     struct zwp_locked_pointer_v1 *locked_pointer;
  1063 
  1064     if (w->locked_pointer)
  1065         return;
  1066 
  1067     locked_pointer =
  1068         zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
  1069                                                 w->surface,
  1070                                                 input->pointer,
  1071                                                 NULL,
  1072                                                 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
  1073     zwp_locked_pointer_v1_add_listener(locked_pointer,
  1074                                        &locked_pointer_listener,
  1075                                        window);
  1076 
  1077     w->locked_pointer = locked_pointer;
  1078 }
  1079 
  1080 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
  1081 {
  1082     SDL_VideoDevice *vd = SDL_GetVideoDevice();
  1083     SDL_VideoData *d = input->display;
  1084     SDL_Window *window;
  1085     struct zwp_relative_pointer_v1 *relative_pointer;
  1086 
  1087     if (!d->relative_pointer_manager)
  1088         return -1;
  1089 
  1090     if (!d->pointer_constraints)
  1091         return -1;
  1092 
  1093     if (!input->relative_pointer) {
  1094         relative_pointer =
  1095             zwp_relative_pointer_manager_v1_get_relative_pointer(
  1096                 d->relative_pointer_manager,
  1097                 input->pointer);
  1098         zwp_relative_pointer_v1_add_listener(relative_pointer,
  1099                                              &relative_pointer_listener,
  1100                                              input);
  1101         input->relative_pointer = relative_pointer;
  1102     }
  1103 
  1104     for (window = vd->windows; window; window = window->next)
  1105         lock_pointer_to_window(window, input);
  1106 
  1107     d->relative_mouse_mode = 1;
  1108 
  1109     return 0;
  1110 }
  1111 
  1112 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
  1113 {
  1114     SDL_VideoDevice *vd = SDL_GetVideoDevice();
  1115     SDL_VideoData *d = input->display;
  1116     SDL_Window *window;
  1117     SDL_WindowData *w;
  1118 
  1119     for (window = vd->windows; window; window = window->next) {
  1120         w = window->driverdata;
  1121         if (w->locked_pointer)
  1122             zwp_locked_pointer_v1_destroy(w->locked_pointer);
  1123         w->locked_pointer = NULL;
  1124     }
  1125 
  1126     zwp_relative_pointer_v1_destroy(input->relative_pointer);
  1127     input->relative_pointer = NULL;
  1128 
  1129     d->relative_mouse_mode = 0;
  1130 
  1131     return 0;
  1132 }
  1133 
  1134 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
  1135 
  1136 /* vi: set ts=4 sw=4 expandtab: */