src/video/wayland/SDL_waylandevents.c
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10737 3406a0f8b041
child 11296 44853f387017
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 "../../events/SDL_sysevents.h"
    31 #include "../../events/SDL_events_c.h"
    32 #include "../../events/scancodes_xfree86.h"
    33 
    34 #include "SDL_waylandvideo.h"
    35 #include "SDL_waylandevents_c.h"
    36 #include "SDL_waylandwindow.h"
    37 
    38 #include "SDL_waylanddyn.h"
    39 
    40 #include "pointer-constraints-unstable-v1-client-protocol.h"
    41 #include "relative-pointer-unstable-v1-client-protocol.h"
    42 
    43 #include <linux/input.h>
    44 #include <sys/select.h>
    45 #include <sys/mman.h>
    46 #include <poll.h>
    47 #include <unistd.h>
    48 #include <xkbcommon/xkbcommon.h>
    49 
    50 struct SDL_WaylandInput {
    51     SDL_VideoData *display;
    52     struct wl_seat *seat;
    53     struct wl_pointer *pointer;
    54     struct wl_keyboard *keyboard;
    55     SDL_WaylandDataDevice *data_device;
    56     struct zwp_relative_pointer_v1 *relative_pointer;
    57     SDL_WindowData *pointer_focus;
    58     SDL_WindowData *keyboard_focus;
    59 
    60     /* Last motion location */
    61     wl_fixed_t sx_w;
    62     wl_fixed_t sy_w;
    63 
    64     double dx_frac;
    65     double dy_frac;
    66 
    67     struct {
    68         struct xkb_keymap *keymap;
    69         struct xkb_state *state;
    70     } xkb;
    71 };
    72 
    73 void
    74 Wayland_PumpEvents(_THIS)
    75 {
    76     SDL_VideoData *d = _this->driverdata;
    77     struct pollfd pfd[1];
    78 
    79     pfd[0].fd = WAYLAND_wl_display_get_fd(d->display);
    80     pfd[0].events = POLLIN;
    81     poll(pfd, 1, 0);
    82 
    83     if (pfd[0].revents & POLLIN)
    84         WAYLAND_wl_display_dispatch(d->display);
    85     else
    86         WAYLAND_wl_display_dispatch_pending(d->display);
    87 }
    88 
    89 static void
    90 pointer_handle_enter(void *data, struct wl_pointer *pointer,
    91                      uint32_t serial, struct wl_surface *surface,
    92                      wl_fixed_t sx_w, wl_fixed_t sy_w)
    93 {
    94     struct SDL_WaylandInput *input = data;
    95     SDL_WindowData *window;
    96 
    97     if (!surface) {
    98         /* enter event for a window we've just destroyed */
    99         return;
   100     }
   101     
   102     /* This handler will be called twice in Wayland 1.4
   103      * Once for the window surface which has valid user data
   104      * and again for the mouse cursor surface which does not have valid user data
   105      * We ignore the later
   106      */
   107 
   108     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
   109     
   110     if (window) {
   111         input->pointer_focus = window;
   112         SDL_SetMouseFocus(window->sdlwindow);
   113     }
   114 }
   115 
   116 static void
   117 pointer_handle_leave(void *data, struct wl_pointer *pointer,
   118                      uint32_t serial, struct wl_surface *surface)
   119 {
   120     struct SDL_WaylandInput *input = data;
   121 
   122     if (input->pointer_focus) {
   123         SDL_SetMouseFocus(NULL);
   124         input->pointer_focus = NULL;
   125     }
   126 }
   127 
   128 static void
   129 pointer_handle_motion(void *data, struct wl_pointer *pointer,
   130                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
   131 {
   132     struct SDL_WaylandInput *input = data;
   133     SDL_WindowData *window = input->pointer_focus;
   134     input->sx_w = sx_w;
   135     input->sy_w = sy_w;
   136     if (input->pointer_focus) {
   137         const int sx = wl_fixed_to_int(sx_w);
   138         const int sy = wl_fixed_to_int(sy_w);
   139         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
   140     }
   141 }
   142 
   143 static SDL_bool
   144 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
   145 {
   146     SDL_WindowData *window_data = input->pointer_focus;
   147     SDL_Window *window = window_data->sdlwindow;
   148 
   149     if (window->hit_test) {
   150         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
   151         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
   152         static const uint32_t directions[] = {
   153             WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
   154             WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
   155             WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
   156             WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
   157         };
   158         switch (rc) {
   159             case SDL_HITTEST_DRAGGABLE:
   160                 wl_shell_surface_move(window_data->shell_surface, input->seat, serial);
   161                 return SDL_TRUE;
   162 
   163             case SDL_HITTEST_RESIZE_TOPLEFT:
   164             case SDL_HITTEST_RESIZE_TOP:
   165             case SDL_HITTEST_RESIZE_TOPRIGHT:
   166             case SDL_HITTEST_RESIZE_RIGHT:
   167             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
   168             case SDL_HITTEST_RESIZE_BOTTOM:
   169             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
   170             case SDL_HITTEST_RESIZE_LEFT:
   171                 wl_shell_surface_resize(window_data->shell_surface, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   172                 return SDL_TRUE;
   173 
   174             default: return SDL_FALSE;
   175         }
   176     }
   177 
   178     return SDL_FALSE;
   179 }
   180 
   181 static void
   182 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
   183                              uint32_t time, uint32_t button, uint32_t state_w)
   184 {
   185     SDL_WindowData *window = input->pointer_focus;
   186     enum wl_pointer_button_state state = state_w;
   187     uint32_t sdl_button;
   188     
   189     if  (input->pointer_focus) {
   190         switch (button) {
   191             case BTN_LEFT:
   192                 sdl_button = SDL_BUTTON_LEFT;
   193                 if (ProcessHitTest(input, serial)) {
   194                     return;  /* don't pass this event on to app. */
   195                 }
   196                 break;
   197             case BTN_MIDDLE:
   198                 sdl_button = SDL_BUTTON_MIDDLE;
   199                 break;
   200             case BTN_RIGHT:
   201                 sdl_button = SDL_BUTTON_RIGHT;
   202                 break;
   203             case BTN_SIDE:
   204                 sdl_button = SDL_BUTTON_X1;
   205                 break;
   206             case BTN_EXTRA:
   207                 sdl_button = SDL_BUTTON_X2;
   208                 break;
   209             default:
   210                 return;
   211         }
   212             
   213         Wayland_data_device_set_serial(input->data_device, serial); 
   214 
   215         SDL_SendMouseButton(window->sdlwindow, 0,
   216                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   217     }
   218 }
   219 
   220 static void
   221 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
   222                       uint32_t time, uint32_t button, uint32_t state_w)
   223 {
   224     struct SDL_WaylandInput *input = data;
   225 
   226     pointer_handle_button_common(input, serial, time, button, state_w);
   227 }
   228 
   229 static void
   230 pointer_handle_axis_common(struct SDL_WaylandInput *input,
   231                            uint32_t time, uint32_t axis, wl_fixed_t value)
   232 {
   233     SDL_WindowData *window = input->pointer_focus;
   234     enum wl_pointer_axis a = axis;
   235     int x, y;
   236 
   237     if (input->pointer_focus) {
   238         switch (a) {
   239             case WL_POINTER_AXIS_VERTICAL_SCROLL:
   240                 x = 0;
   241                 y = wl_fixed_to_int(value);
   242                 break;
   243             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
   244                 x = wl_fixed_to_int(value);
   245                 y = 0;
   246                 break;
   247             default:
   248                 return;
   249         }
   250 
   251         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
   252     }
   253 }
   254 
   255 static void
   256 pointer_handle_axis(void *data, struct wl_pointer *pointer,
   257                     uint32_t time, uint32_t axis, wl_fixed_t value)
   258 {
   259     struct SDL_WaylandInput *input = data;
   260 
   261     pointer_handle_axis_common(input, time, axis, value);
   262 }
   263 
   264 static const struct wl_pointer_listener pointer_listener = {
   265     pointer_handle_enter,
   266     pointer_handle_leave,
   267     pointer_handle_motion,
   268     pointer_handle_button,
   269     pointer_handle_axis,
   270 };
   271 
   272 static void
   273 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
   274                        uint32_t format, int fd, uint32_t size)
   275 {
   276     struct SDL_WaylandInput *input = data;
   277     char *map_str;
   278 
   279     if (!data) {
   280         close(fd);
   281         return;
   282     }
   283 
   284     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
   285         close(fd);
   286         return;
   287     }
   288 
   289     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
   290     if (map_str == MAP_FAILED) {
   291         close(fd);
   292         return;
   293     }
   294 
   295     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
   296                                                 map_str,
   297                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
   298                                                 0);
   299     munmap(map_str, size);
   300     close(fd);
   301 
   302     if (!input->xkb.keymap) {
   303         fprintf(stderr, "failed to compile keymap\n");
   304         return;
   305     }
   306 
   307     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
   308     if (!input->xkb.state) {
   309         fprintf(stderr, "failed to create XKB state\n");
   310         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   311         input->xkb.keymap = NULL;
   312         return;
   313     }
   314 }
   315 
   316 static void
   317 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
   318                       uint32_t serial, struct wl_surface *surface,
   319                       struct wl_array *keys)
   320 {
   321     struct SDL_WaylandInput *input = data;
   322     SDL_WindowData *window;
   323 
   324     if (!surface) {
   325         /* enter event for a window we've just destroyed */
   326         return;
   327     }
   328  
   329     window = wl_surface_get_user_data(surface);
   330 
   331     if (window) {
   332         input->keyboard_focus = window;
   333         window->keyboard_device = input;
   334         SDL_SetKeyboardFocus(window->sdlwindow);
   335     }
   336 }
   337 
   338 static void
   339 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
   340                       uint32_t serial, struct wl_surface *surface)
   341 {
   342     SDL_SetKeyboardFocus(NULL);
   343 }
   344 
   345 static void
   346 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
   347                     uint32_t serial, uint32_t time, uint32_t key,
   348                     uint32_t state_w)
   349 {
   350     struct SDL_WaylandInput *input = data;
   351     SDL_WindowData *window = input->keyboard_focus;
   352     enum wl_keyboard_key_state state = state_w;
   353     const xkb_keysym_t *syms;
   354     uint32_t scancode;
   355     char text[8];
   356     int size;
   357 
   358     if (key < SDL_arraysize(xfree86_scancode_table2)) {
   359         scancode = xfree86_scancode_table2[key];
   360 
   361         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
   362         if (scancode != SDL_SCANCODE_UNKNOWN)
   363             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
   364                                 SDL_PRESSED : SDL_RELEASED, scancode);
   365     }
   366 
   367     if (!window || window->keyboard_device != input || !input->xkb.state)
   368         return;
   369 
   370     // TODO can this happen?
   371     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
   372         return;
   373 
   374     if (state) {
   375         size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
   376 
   377         if (size > 0) {
   378             text[size] = 0;
   379 
   380             Wayland_data_device_set_serial(input->data_device, serial);
   381 
   382             SDL_SendKeyboardText(text);
   383         }
   384     }
   385 }
   386 
   387 static void
   388 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
   389                           uint32_t serial, uint32_t mods_depressed,
   390                           uint32_t mods_latched, uint32_t mods_locked,
   391                           uint32_t group)
   392 {
   393     struct SDL_WaylandInput *input = data;
   394 
   395     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
   396                           mods_locked, 0, 0, group);
   397 }
   398 
   399 static const struct wl_keyboard_listener keyboard_listener = {
   400     keyboard_handle_keymap,
   401     keyboard_handle_enter,
   402     keyboard_handle_leave,
   403     keyboard_handle_key,
   404     keyboard_handle_modifiers,
   405 };
   406 
   407 static void
   408 seat_handle_capabilities(void *data, struct wl_seat *seat,
   409                          enum wl_seat_capability caps)
   410 {
   411     struct SDL_WaylandInput *input = data;
   412 
   413     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
   414         input->pointer = wl_seat_get_pointer(seat);
   415         input->display->pointer = input->pointer;
   416         wl_pointer_set_user_data(input->pointer, input);
   417         wl_pointer_add_listener(input->pointer, &pointer_listener,
   418                                 input);
   419     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
   420         wl_pointer_destroy(input->pointer);
   421         input->pointer = NULL;
   422     }
   423 
   424     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
   425         input->keyboard = wl_seat_get_keyboard(seat);
   426         wl_keyboard_set_user_data(input->keyboard, input);
   427         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
   428                                  input);
   429     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
   430         wl_keyboard_destroy(input->keyboard);
   431         input->keyboard = NULL;
   432     }
   433 }
   434 
   435 static const struct wl_seat_listener seat_listener = {
   436     seat_handle_capabilities,
   437 };
   438 
   439 static void
   440 data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
   441                           const char *mime_type)
   442 {
   443 }
   444 
   445 static void
   446 data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
   447                         const char *mime_type, int32_t fd)
   448 {
   449     Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
   450 }
   451                        
   452 static void
   453 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
   454 {
   455     Wayland_data_source_destroy(data);
   456 }
   457                        
   458 static void
   459 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
   460 {
   461 }
   462 
   463 static void
   464 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
   465 {
   466 }
   467 
   468 static void
   469 data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
   470                           uint32_t dnd_action)
   471 {
   472 }
   473 
   474 static const struct wl_data_source_listener data_source_listener = {
   475     data_source_handle_target,
   476     data_source_handle_send,
   477     data_source_handle_cancelled,
   478     data_source_handle_dnd_drop_performed, // Version 3
   479     data_source_handle_dnd_finished,       // Version 3
   480     data_source_handle_action,             // Version 3
   481 };
   482 
   483 SDL_WaylandDataSource*
   484 Wayland_data_source_create(_THIS)
   485 {
   486     SDL_WaylandDataSource *data_source = NULL;
   487     SDL_VideoData *driver_data = NULL;
   488     struct wl_data_source *id = NULL;
   489 
   490     if (_this == NULL || _this->driverdata == NULL) {
   491         SDL_SetError("Video driver uninitialized");
   492     } else {
   493         driver_data = _this->driverdata;
   494 
   495         if (driver_data->data_device_manager != NULL) {
   496             id = wl_data_device_manager_create_data_source(
   497                      driver_data->data_device_manager);
   498         }
   499 
   500         if (id == NULL) { 
   501             SDL_SetError("Wayland unable to create data source");
   502         } else {
   503             data_source = SDL_calloc(1, sizeof *data_source);
   504             if (data_source == NULL) {
   505                 SDL_OutOfMemory();
   506                 wl_data_source_destroy(id);
   507             } else {
   508                 WAYLAND_wl_list_init(&(data_source->mimes));
   509                 data_source->source = id;
   510                 wl_data_source_set_user_data(id, data_source);
   511                 wl_data_source_add_listener(id, &data_source_listener,
   512                                             data_source);
   513             }
   514         }
   515     }
   516     return data_source;
   517 }
   518 
   519 static void
   520 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
   521                         const char *mime_type)
   522 {
   523     SDL_WaylandDataOffer *offer = data;
   524     Wayland_data_offer_add_mime(offer, mime_type);
   525 }
   526 
   527 static void
   528 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
   529                                  uint32_t source_actions)
   530 {
   531 }
   532 
   533 static void
   534 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
   535                           uint32_t dnd_action)
   536 {
   537 }
   538 
   539 static const struct wl_data_offer_listener data_offer_listener = {
   540     data_offer_handle_offer,
   541     data_offer_handle_source_actions, // Version 3
   542     data_offer_handle_actions,        // Version 3
   543 };
   544 
   545 static void
   546 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
   547 			                  struct wl_data_offer *id)
   548 {
   549     SDL_WaylandDataOffer *data_offer = NULL;
   550 
   551     data_offer = SDL_calloc(1, sizeof *data_offer);
   552     if (data_offer == NULL) {
   553         SDL_OutOfMemory();
   554     } else {
   555         data_offer->offer = id;
   556         data_offer->data_device = data;
   557         WAYLAND_wl_list_init(&(data_offer->mimes));
   558         wl_data_offer_set_user_data(id, data_offer);
   559         wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
   560     }
   561 }
   562 
   563 static void
   564 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
   565 		                 uint32_t serial, struct wl_surface *surface,
   566                          wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
   567 {
   568     SDL_WaylandDataDevice *data_device = data;
   569     SDL_bool has_mime = SDL_FALSE;
   570     uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; 
   571         
   572     data_device->drag_serial = serial;
   573 
   574     if (id != NULL) {
   575         data_device->drag_offer = wl_data_offer_get_user_data(id);
   576 
   577         /* TODO: SDL Support more mime types */
   578         has_mime = Wayland_data_offer_has_mime(
   579             data_device->drag_offer, FILE_MIME);
   580 
   581         /* If drag_mime is NULL this will decline the offer */
   582         wl_data_offer_accept(id, serial,
   583                              (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
   584 
   585         /* SDL only supports "copy" style drag and drop */
   586         if (has_mime == SDL_TRUE) {
   587             dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
   588         }
   589         wl_data_offer_set_actions(data_device->drag_offer->offer,
   590                                   dnd_action, dnd_action);
   591     }
   592 }
   593 
   594 static void
   595 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
   596 {
   597     SDL_WaylandDataDevice *data_device = data;
   598     SDL_WaylandDataOffer *offer = NULL;
   599 
   600     if (data_device->selection_offer != NULL) {
   601         data_device->selection_offer = NULL;
   602         Wayland_data_offer_destroy(offer);
   603     }
   604 }
   605 
   606 static void
   607 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
   608 		                  uint32_t time, wl_fixed_t x, wl_fixed_t y)
   609 {
   610 }
   611 
   612 static void
   613 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
   614 {
   615     SDL_WaylandDataDevice *data_device = data;
   616     void *buffer = NULL;
   617     size_t length = 0;
   618 
   619     const char *current_uri = NULL;
   620     const char *last_char = NULL;
   621     char *current_char = NULL;
   622     
   623     if (data_device->drag_offer != NULL) {
   624         /* TODO: SDL Support more mime types */
   625         buffer = Wayland_data_offer_receive(data_device->drag_offer,
   626                                             &length, FILE_MIME, SDL_FALSE);
   627 
   628         /* uri-list */
   629         current_uri = (const char *)buffer;
   630         last_char = (const char *)buffer + length;
   631         for (current_char = buffer; current_char < last_char; ++current_char) {
   632             if (*current_char == '\n' || *current_char == 0) {
   633                 if (*current_uri != 0 && *current_uri != '#') {
   634                     *current_char = 0;
   635                     SDL_SendDropFile(NULL, current_uri);
   636                 }
   637                 current_uri = (const char *)current_char + 1;
   638             }
   639         }
   640 
   641         SDL_free(buffer);
   642     }
   643 }
   644 
   645 static void
   646 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
   647 			                 struct wl_data_offer *id)
   648 {    
   649     SDL_WaylandDataDevice *data_device = data;
   650     SDL_WaylandDataOffer *offer = NULL;
   651 
   652     if (id != NULL) {
   653         offer = wl_data_offer_get_user_data(id);
   654     }
   655 
   656     if (data_device->selection_offer != offer) {
   657         Wayland_data_offer_destroy(data_device->selection_offer);
   658         data_device->selection_offer = offer;
   659     }
   660 
   661     SDL_SendClipboardUpdate();
   662 }
   663 
   664 static const struct wl_data_device_listener data_device_listener = {
   665     data_device_handle_data_offer,
   666     data_device_handle_enter,
   667     data_device_handle_leave,
   668     data_device_handle_motion,
   669     data_device_handle_drop,
   670     data_device_handle_selection
   671 };
   672 
   673 void
   674 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
   675 {
   676     struct SDL_WaylandInput *input;
   677     SDL_WaylandDataDevice *data_device = NULL;
   678 
   679     input = SDL_calloc(1, sizeof *input);
   680     if (input == NULL)
   681         return;
   682 
   683     input->display = d;
   684     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
   685     input->sx_w = wl_fixed_from_int(0);
   686     input->sy_w = wl_fixed_from_int(0);
   687     d->input = input;
   688     
   689     if (d->data_device_manager != NULL) {
   690         data_device = SDL_calloc(1, sizeof *data_device);
   691         if (data_device == NULL) {
   692             return;
   693         }
   694 
   695         data_device->data_device = wl_data_device_manager_get_data_device(
   696             d->data_device_manager, input->seat
   697         );
   698         data_device->video_data = d;
   699 
   700         if (data_device->data_device == NULL) {
   701             SDL_free(data_device);
   702         } else {
   703             wl_data_device_set_user_data(data_device->data_device, data_device);
   704             wl_data_device_add_listener(data_device->data_device,
   705                                         &data_device_listener, data_device);
   706             input->data_device = data_device;
   707         }
   708     }
   709 
   710     wl_seat_add_listener(input->seat, &seat_listener, input);
   711     wl_seat_set_user_data(input->seat, input);
   712 
   713     WAYLAND_wl_display_flush(d->display);
   714 }
   715 
   716 void Wayland_display_destroy_input(SDL_VideoData *d)
   717 {
   718     struct SDL_WaylandInput *input = d->input;
   719 
   720     if (!input)
   721         return;
   722 
   723     if (input->data_device != NULL) {
   724         Wayland_data_device_clear_selection(input->data_device);
   725         if (input->data_device->selection_offer != NULL) {
   726             Wayland_data_offer_destroy(input->data_device->selection_offer);
   727         }
   728         if (input->data_device->drag_offer != NULL) {
   729             Wayland_data_offer_destroy(input->data_device->drag_offer);
   730         }
   731         if (input->data_device->data_device != NULL) {
   732             wl_data_device_release(input->data_device->data_device);
   733         }
   734         SDL_free(input->data_device);
   735     }
   736 
   737     if (input->keyboard)
   738         wl_keyboard_destroy(input->keyboard);
   739 
   740     if (input->pointer)
   741         wl_pointer_destroy(input->pointer);
   742 
   743     if (input->seat)
   744         wl_seat_destroy(input->seat);
   745 
   746     if (input->xkb.state)
   747         WAYLAND_xkb_state_unref(input->xkb.state);
   748 
   749     if (input->xkb.keymap)
   750         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   751 
   752     SDL_free(input);
   753     d->input = NULL;
   754 }
   755 
   756 SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
   757 {
   758     if (input == NULL) {
   759         return NULL;
   760     }
   761 
   762     return input->data_device;
   763 }
   764 
   765 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
   766 {
   767     d->relative_pointer_manager =
   768         wl_registry_bind(d->registry, id,
   769                          &zwp_relative_pointer_manager_v1_interface, 1);
   770 }
   771 
   772 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
   773 {
   774     if (d->relative_pointer_manager)
   775         zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
   776 }
   777 
   778 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
   779 {
   780     d->pointer_constraints =
   781         wl_registry_bind(d->registry, id,
   782                          &zwp_pointer_constraints_v1_interface, 1);
   783 }
   784 
   785 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
   786 {
   787     if (d->pointer_constraints)
   788         zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
   789 }
   790 
   791 static void
   792 relative_pointer_handle_relative_motion(void *data,
   793                                         struct zwp_relative_pointer_v1 *pointer,
   794                                         uint32_t time_hi,
   795                                         uint32_t time_lo,
   796                                         wl_fixed_t dx_w,
   797                                         wl_fixed_t dy_w,
   798                                         wl_fixed_t dx_unaccel_w,
   799                                         wl_fixed_t dy_unaccel_w)
   800 {
   801     struct SDL_WaylandInput *input = data;
   802     SDL_VideoData *d = input->display;
   803     SDL_WindowData *window = input->pointer_focus;
   804     double dx_unaccel;
   805     double dy_unaccel;
   806     double dx;
   807     double dy;
   808 
   809     dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
   810     dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
   811 
   812     /* Add left over fraction from last event. */
   813     dx_unaccel += input->dx_frac;
   814     dy_unaccel += input->dy_frac;
   815 
   816     input->dx_frac = modf(dx_unaccel, &dx);
   817     input->dy_frac = modf(dy_unaccel, &dy);
   818 
   819     if (input->pointer_focus && d->relative_mouse_mode) {
   820         SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
   821     }
   822 }
   823 
   824 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
   825     relative_pointer_handle_relative_motion,
   826 };
   827 
   828 static void
   829 locked_pointer_locked(void *data,
   830                       struct zwp_locked_pointer_v1 *locked_pointer)
   831 {
   832 }
   833 
   834 static void
   835 locked_pointer_unlocked(void *data,
   836                         struct zwp_locked_pointer_v1 *locked_pointer)
   837 {
   838 }
   839 
   840 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
   841     locked_pointer_locked,
   842     locked_pointer_unlocked,
   843 };
   844 
   845 static void
   846 lock_pointer_to_window(SDL_Window *window,
   847                        struct SDL_WaylandInput *input)
   848 {
   849     SDL_WindowData *w = window->driverdata;
   850     SDL_VideoData *d = input->display;
   851     struct zwp_locked_pointer_v1 *locked_pointer;
   852 
   853     if (w->locked_pointer)
   854         return;
   855 
   856     locked_pointer =
   857         zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
   858                                                 w->surface,
   859                                                 input->pointer,
   860                                                 NULL,
   861                                                 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
   862     zwp_locked_pointer_v1_add_listener(locked_pointer,
   863                                        &locked_pointer_listener,
   864                                        window);
   865 
   866     w->locked_pointer = locked_pointer;
   867 }
   868 
   869 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
   870 {
   871     SDL_VideoDevice *vd = SDL_GetVideoDevice();
   872     SDL_VideoData *d = input->display;
   873     SDL_Window *window;
   874     struct zwp_relative_pointer_v1 *relative_pointer;
   875 
   876     if (!d->relative_pointer_manager)
   877         return -1;
   878 
   879     if (!d->pointer_constraints)
   880         return -1;
   881 
   882     if (!input->relative_pointer) {
   883         relative_pointer =
   884             zwp_relative_pointer_manager_v1_get_relative_pointer(
   885                 d->relative_pointer_manager,
   886                 input->pointer);
   887         zwp_relative_pointer_v1_add_listener(relative_pointer,
   888                                              &relative_pointer_listener,
   889                                              input);
   890         input->relative_pointer = relative_pointer;
   891     }
   892 
   893     for (window = vd->windows; window; window = window->next)
   894         lock_pointer_to_window(window, input);
   895 
   896     d->relative_mouse_mode = 1;
   897 
   898     return 0;
   899 }
   900 
   901 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
   902 {
   903     SDL_VideoDevice *vd = SDL_GetVideoDevice();
   904     SDL_VideoData *d = input->display;
   905     SDL_Window *window;
   906     SDL_WindowData *w;
   907 
   908     for (window = vd->windows; window; window = window->next) {
   909         w = window->driverdata;
   910         if (w->locked_pointer)
   911             zwp_locked_pointer_v1_destroy(w->locked_pointer);
   912         w->locked_pointer = NULL;
   913     }
   914 
   915     zwp_relative_pointer_v1_destroy(input->relative_pointer);
   916     input->relative_pointer = NULL;
   917 
   918     d->relative_mouse_mode = 0;
   919 
   920     return 0;
   921 }
   922 
   923 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   924 
   925 /* vi: set ts=4 sw=4 expandtab: */