src/video/wayland/SDL_waylandevents.c
author Sam Lantinga
Mon, 19 Oct 2020 17:29:16 -0700
changeset 14174 71e97db0ba5d
parent 14173 d3fa6ce33db3
permissions -rw-r--r--
Removed debug log message
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2020 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_timer.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 #ifdef SDL_INPUT_LINUXEV
    47 #include <linux/input.h>
    48 #else
    49 #define BTN_LEFT    (0x110)
    50 #define BTN_RIGHT   (0x111)
    51 #define BTN_MIDDLE  (0x112)
    52 #define BTN_SIDE    (0x113)
    53 #define BTN_EXTRA   (0x114)
    54 #endif
    55 #include <sys/select.h>
    56 #include <sys/mman.h>
    57 #include <poll.h>
    58 #include <unistd.h>
    59 #include <xkbcommon/xkbcommon.h>
    60 
    61 typedef struct {
    62     // repeat_rate in range of [1, 1000]
    63     int32_t repeat_rate;
    64     int32_t repeat_delay;
    65     SDL_bool is_initialized;
    66 
    67     SDL_bool is_key_down;
    68     uint32_t next_repeat_ms;
    69     uint32_t scancode;
    70     char text[8];
    71 } SDL_WaylandKeyboardRepeat;
    72 
    73 struct SDL_WaylandInput {
    74     SDL_VideoData *display;
    75     struct wl_seat *seat;
    76     struct wl_pointer *pointer;
    77     struct wl_touch *touch;
    78     struct wl_keyboard *keyboard;
    79     SDL_WaylandDataDevice *data_device;
    80     struct zwp_relative_pointer_v1 *relative_pointer;
    81     struct zwp_confined_pointer_v1 *confined_pointer;
    82     SDL_Window *confined_pointer_window;
    83     SDL_WindowData *pointer_focus;
    84     SDL_WindowData *keyboard_focus;
    85 
    86     /* Last motion location */
    87     wl_fixed_t sx_w;
    88     wl_fixed_t sy_w;
    89 
    90     double dx_frac;
    91     double dy_frac;
    92 
    93     struct {
    94         struct xkb_keymap *keymap;
    95         struct xkb_state *state;
    96     } xkb;
    97 
    98     /* information about axis events on current frame */
    99     struct {
   100         SDL_bool is_x_discrete;
   101         float x;
   102 
   103         SDL_bool is_y_discrete;
   104         float y;
   105     } pointer_curr_axis_info;
   106 
   107     SDL_WaylandKeyboardRepeat keyboard_repeat;
   108 };
   109 
   110 struct SDL_WaylandTouchPoint {
   111     SDL_TouchID id;
   112     float x;
   113     float y;
   114     struct wl_surface* surface;
   115 
   116     struct SDL_WaylandTouchPoint* prev;
   117     struct SDL_WaylandTouchPoint* next;
   118 };
   119 
   120 struct SDL_WaylandTouchPointList {
   121     struct SDL_WaylandTouchPoint* head;
   122     struct SDL_WaylandTouchPoint* tail;
   123 };
   124 
   125 static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
   126 
   127 static void
   128 touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
   129 {
   130     struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
   131 
   132     tp->id = id;
   133     tp->x = x;
   134     tp->y = y;
   135     tp->surface = surface;
   136 
   137     if (touch_points.tail) {
   138         touch_points.tail->next = tp;
   139         tp->prev = touch_points.tail;
   140     } else {
   141         touch_points.head = tp;
   142         tp->prev = NULL;
   143     }
   144 
   145     touch_points.tail = tp;
   146     tp->next = NULL;
   147 }
   148 
   149 static void
   150 touch_update(SDL_TouchID id, float x, float y)
   151 {
   152     struct SDL_WaylandTouchPoint* tp = touch_points.head;
   153 
   154     while (tp) {
   155         if (tp->id == id) {
   156             tp->x = x;
   157             tp->y = y;
   158         }
   159 
   160         tp = tp->next;
   161     }
   162 }
   163 
   164 static void
   165 touch_del(SDL_TouchID id, float* x, float* y, struct wl_surface **surface)
   166 {
   167     struct SDL_WaylandTouchPoint* tp = touch_points.head;
   168 
   169     while (tp) {
   170         if (tp->id == id) {
   171             *x = tp->x;
   172             *y = tp->y;
   173             *surface = tp->surface;
   174 
   175             if (tp->prev) {
   176                 tp->prev->next = tp->next;
   177             } else {
   178                 touch_points.head = tp->next;
   179             }
   180 
   181             if (tp->next) {
   182                 tp->next->prev = tp->prev;
   183             } else {
   184                 touch_points.tail = tp->prev;
   185             }
   186 
   187             {
   188                 struct SDL_WaylandTouchPoint *next = tp->next;
   189                 SDL_free(tp);
   190                 tp = next;
   191             }
   192         } else {
   193             tp = tp->next;
   194         }
   195     }
   196 }
   197 
   198 static struct wl_surface*
   199 touch_surface(SDL_TouchID id)
   200 {
   201     struct SDL_WaylandTouchPoint* tp = touch_points.head;
   202 
   203     while (tp) {
   204         if (tp->id == id) {
   205             return tp->surface;
   206         }
   207 
   208         tp = tp->next;
   209     }
   210 
   211     return NULL;
   212 }
   213 
   214 /* Returns the time till next repeat, or 0 if no key is down. */
   215 static void
   216 keyboard_repeat_handle(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t now)
   217 {
   218     if (!repeat_info->is_key_down || !repeat_info->is_initialized) {
   219         return;
   220     }
   221     while (repeat_info->next_repeat_ms <= now) {
   222         if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
   223             SDL_SendKeyboardKey(SDL_PRESSED, repeat_info->scancode);
   224         }
   225         if (repeat_info->text[0]) {
   226             SDL_SendKeyboardText(repeat_info->text);
   227         }
   228         repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate;
   229     }
   230 }
   231 
   232 static void
   233 keyboard_repeat_clear(SDL_WaylandKeyboardRepeat* repeat_info) {
   234     if (!repeat_info->is_initialized) {
   235         return;
   236     }
   237     repeat_info->is_key_down = SDL_FALSE;
   238 }
   239 
   240 static void
   241 keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info,
   242                     uint32_t scancode, SDL_bool has_text, char text[8]) {
   243     if (!repeat_info->is_initialized) {
   244         return;
   245     }
   246     repeat_info->is_key_down = SDL_TRUE;
   247     repeat_info->next_repeat_ms = SDL_GetTicks() + repeat_info->repeat_delay;
   248     repeat_info->scancode = scancode;
   249     if (has_text) {
   250         memcpy(repeat_info->text, text, 8);
   251     } else {
   252         repeat_info->text[0] = '\0';
   253     }
   254 }
   255 
   256 void
   257 Wayland_PumpEvents(_THIS)
   258 {
   259     SDL_VideoData *d = _this->driverdata;
   260     struct SDL_WaylandInput *input = d->input;
   261     int err;
   262 
   263     WAYLAND_wl_display_flush(d->display);
   264 
   265     if (input) {
   266         uint32_t now = SDL_GetTicks();
   267         keyboard_repeat_handle(&input->keyboard_repeat, now);
   268     }
   269 
   270     if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
   271         err = WAYLAND_wl_display_dispatch(d->display);
   272     } else {
   273         err = WAYLAND_wl_display_dispatch_pending(d->display);
   274     }
   275     if (err == -1 && !d->display_disconnected) {
   276         /* Something has failed with the Wayland connection -- for example,
   277          * the compositor may have shut down and closed its end of the socket,
   278          * or there is a library-specific error. No recovery is possible. */
   279         d->display_disconnected = 1;
   280         /* Only send a single quit message, as application shutdown might call
   281          * SDL_PumpEvents */
   282         SDL_SendQuit();
   283     }
   284 }
   285 
   286 static void
   287 pointer_handle_motion(void *data, struct wl_pointer *pointer,
   288                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
   289 {
   290     struct SDL_WaylandInput *input = data;
   291     SDL_WindowData *window = input->pointer_focus;
   292     input->sx_w = sx_w;
   293     input->sy_w = sy_w;
   294     if (input->pointer_focus) {
   295         const int sx = wl_fixed_to_int(sx_w);
   296         const int sy = wl_fixed_to_int(sy_w);
   297         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
   298     }
   299 }
   300 
   301 static void
   302 pointer_handle_enter(void *data, struct wl_pointer *pointer,
   303                      uint32_t serial, struct wl_surface *surface,
   304                      wl_fixed_t sx_w, wl_fixed_t sy_w)
   305 {
   306     struct SDL_WaylandInput *input = data;
   307     SDL_WindowData *window;
   308 
   309     if (!surface) {
   310         /* enter event for a window we've just destroyed */
   311         return;
   312     }
   313 
   314     /* This handler will be called twice in Wayland 1.4
   315      * Once for the window surface which has valid user data
   316      * and again for the mouse cursor surface which does not have valid user data
   317      * We ignore the later
   318      */
   319 
   320     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
   321 
   322     if (window) {
   323         input->pointer_focus = window;
   324         SDL_SetMouseFocus(window->sdlwindow);
   325         /* In the case of e.g. a pointer confine warp, we may receive an enter
   326          * event with no following motion event, but with the new coordinates
   327          * as part of the enter event. */
   328         pointer_handle_motion(data, pointer, serial, sx_w, sy_w);
   329     }
   330 }
   331 
   332 static void
   333 pointer_handle_leave(void *data, struct wl_pointer *pointer,
   334                      uint32_t serial, struct wl_surface *surface)
   335 {
   336     struct SDL_WaylandInput *input = data;
   337 
   338     if (input->pointer_focus) {
   339         SDL_SetMouseFocus(NULL);
   340         input->pointer_focus = NULL;
   341     }
   342 }
   343 
   344 static SDL_bool
   345 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
   346 {
   347     SDL_WindowData *window_data = input->pointer_focus;
   348     SDL_Window *window = window_data->sdlwindow;
   349 
   350     if (window->hit_test) {
   351         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
   352         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
   353 
   354         static const uint32_t directions_wl[] = {
   355             WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
   356             WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
   357             WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
   358             WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
   359         };
   360 
   361         /* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs
   362            WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */
   363         const uint32_t *directions_zxdg = directions_wl;
   364 
   365         switch (rc) {
   366             case SDL_HITTEST_DRAGGABLE:
   367                 if (input->display->shell.xdg) {
   368                     xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial);
   369                 } else if (input->display->shell.zxdg) {
   370                     zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial);
   371                 } else {
   372                     wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial);
   373                 }
   374                 return SDL_TRUE;
   375 
   376             case SDL_HITTEST_RESIZE_TOPLEFT:
   377             case SDL_HITTEST_RESIZE_TOP:
   378             case SDL_HITTEST_RESIZE_TOPRIGHT:
   379             case SDL_HITTEST_RESIZE_RIGHT:
   380             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
   381             case SDL_HITTEST_RESIZE_BOTTOM:
   382             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
   383             case SDL_HITTEST_RESIZE_LEFT:
   384                 if (input->display->shell.xdg) {
   385                     xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   386                 } else if (input->display->shell.zxdg) {
   387                     zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   388                 } else {
   389                     wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
   390                 }
   391                 return SDL_TRUE;
   392 
   393             default: return SDL_FALSE;
   394         }
   395     }
   396 
   397     return SDL_FALSE;
   398 }
   399 
   400 static void
   401 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
   402                              uint32_t time, uint32_t button, uint32_t state_w)
   403 {
   404     SDL_WindowData *window = input->pointer_focus;
   405     enum wl_pointer_button_state state = state_w;
   406     uint32_t sdl_button;
   407 
   408     if  (input->pointer_focus) {
   409         switch (button) {
   410             case BTN_LEFT:
   411                 sdl_button = SDL_BUTTON_LEFT;
   412                 if (ProcessHitTest(input, serial)) {
   413                     return;  /* don't pass this event on to app. */
   414                 }
   415                 break;
   416             case BTN_MIDDLE:
   417                 sdl_button = SDL_BUTTON_MIDDLE;
   418                 break;
   419             case BTN_RIGHT:
   420                 sdl_button = SDL_BUTTON_RIGHT;
   421                 break;
   422             case BTN_SIDE:
   423                 sdl_button = SDL_BUTTON_X1;
   424                 break;
   425             case BTN_EXTRA:
   426                 sdl_button = SDL_BUTTON_X2;
   427                 break;
   428             default:
   429                 return;
   430         }
   431 
   432         Wayland_data_device_set_serial(input->data_device, serial);
   433 
   434         SDL_SendMouseButton(window->sdlwindow, 0,
   435                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
   436     }
   437 }
   438 
   439 static void
   440 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
   441                       uint32_t time, uint32_t button, uint32_t state_w)
   442 {
   443     struct SDL_WaylandInput *input = data;
   444 
   445     pointer_handle_button_common(input, serial, time, button, state_w);
   446 }
   447 
   448 static void
   449 pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
   450                               uint32_t time, uint32_t axis, wl_fixed_t value)
   451 {
   452     SDL_WindowData *window = input->pointer_focus;
   453     enum wl_pointer_axis a = axis;
   454     float x, y;
   455 
   456     if (input->pointer_focus) {
   457         switch (a) {
   458             case WL_POINTER_AXIS_VERTICAL_SCROLL:
   459                 x = 0;
   460                 y = 0 - (float)wl_fixed_to_double(value);
   461                 break;
   462             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
   463                 x = 0 - (float)wl_fixed_to_double(value);
   464                 y = 0;
   465                 break;
   466             default:
   467                 return;
   468         }
   469 
   470         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
   471     }
   472 }
   473 
   474 static void
   475 pointer_handle_axis_common(struct SDL_WaylandInput *input, SDL_bool discrete,
   476                            uint32_t axis, wl_fixed_t value)
   477 {
   478     enum wl_pointer_axis a = axis;
   479 
   480     if (input->pointer_focus) {
   481         switch (a) {
   482             case WL_POINTER_AXIS_VERTICAL_SCROLL:
   483                 if (discrete) {
   484                     /* this is a discrete axis event so we process it and flag
   485                      * to ignore future continuous axis events in this frame */
   486                     input->pointer_curr_axis_info.is_y_discrete = SDL_TRUE;
   487                 } else if(input->pointer_curr_axis_info.is_y_discrete) {
   488                     /* this is a continuous axis event and we have already
   489                      * processed a discrete axis event before so we ignore it */
   490                     break;
   491                 }
   492                 input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
   493                 break;
   494             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
   495                 if (discrete) {
   496                     /* this is a discrete axis event so we process it and flag
   497                      * to ignore future continuous axis events in this frame */
   498                     input->pointer_curr_axis_info.is_x_discrete = SDL_TRUE;
   499                 } else if(input->pointer_curr_axis_info.is_x_discrete) {
   500                     /* this is a continuous axis event and we have already
   501                      * processed a discrete axis event before so we ignore it */
   502                     break;
   503                 }
   504                 input->pointer_curr_axis_info.x = 0 - (float)wl_fixed_to_double(value);
   505                 break;
   506         }
   507     }
   508 }
   509 
   510 static void
   511 pointer_handle_axis(void *data, struct wl_pointer *pointer,
   512                     uint32_t time, uint32_t axis, wl_fixed_t value)
   513 {
   514     struct SDL_WaylandInput *input = data;
   515 
   516     if(wl_seat_get_version(input->seat) >= 5)
   517         pointer_handle_axis_common(input, SDL_FALSE, axis, value);
   518     else
   519         pointer_handle_axis_common_v1(input, time, axis, value);
   520 }
   521 
   522 static void
   523 pointer_handle_frame(void *data, struct wl_pointer *pointer)
   524 {
   525     struct SDL_WaylandInput *input = data;
   526     SDL_WindowData *window = input->pointer_focus;
   527     float x = input->pointer_curr_axis_info.x, y = input->pointer_curr_axis_info.y;
   528 
   529     /* clear pointer_curr_axis_info for next frame */
   530     memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
   531 
   532     if(x == 0.0f && y == 0.0f)
   533         return;
   534     else
   535         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
   536 }
   537 
   538 static void
   539 pointer_handle_axis_source(void *data, struct wl_pointer *pointer,
   540                            uint32_t axis_source)
   541 {
   542     /* unimplemented */
   543 }
   544 
   545 static void
   546 pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
   547                          uint32_t time, uint32_t axis)
   548 {
   549     /* unimplemented */
   550 }
   551 
   552 static void
   553 pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
   554                              uint32_t axis, int32_t discrete)
   555 {
   556     struct SDL_WaylandInput *input = data;
   557 
   558     pointer_handle_axis_common(input, SDL_TRUE, axis, wl_fixed_from_int(discrete));
   559 }
   560 
   561 
   562 static const struct wl_pointer_listener pointer_listener = {
   563     pointer_handle_enter,
   564     pointer_handle_leave,
   565     pointer_handle_motion,
   566     pointer_handle_button,
   567     pointer_handle_axis,
   568     pointer_handle_frame,           // Version 5
   569     pointer_handle_axis_source,     // Version 5
   570     pointer_handle_axis_stop,       // Version 5
   571     pointer_handle_axis_discrete,   // Version 5
   572 };
   573 
   574 static void
   575 touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
   576                    unsigned int timestamp, struct wl_surface *surface,
   577                    int id, wl_fixed_t fx, wl_fixed_t fy)
   578 {
   579     SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
   580     const double dblx = wl_fixed_to_double(fx);
   581     const double dbly = wl_fixed_to_double(fy);
   582     const float x = dblx / window_data->sdlwindow->w;
   583     const float y = dbly / window_data->sdlwindow->h;
   584 
   585     touch_add(id, x, y, surface);
   586 
   587     SDL_SendTouch(1, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f);
   588 }
   589 
   590 static void
   591 touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
   592                  unsigned int timestamp, int id)
   593 {
   594     float x = 0, y = 0;
   595     struct wl_surface *surface = NULL;
   596     SDL_Window *window = NULL;
   597 
   598     touch_del(id, &x, &y, &surface);
   599 
   600     if (surface) {
   601         SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
   602         window = window_data->sdlwindow;
   603     }
   604 
   605     SDL_SendTouch(1, (SDL_FingerID)id, window, SDL_FALSE, x, y, 0.0f);
   606 }
   607 
   608 static void
   609 touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
   610                      int id, wl_fixed_t fx, wl_fixed_t fy)
   611 {
   612     SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
   613     const double dblx = wl_fixed_to_double(fx);
   614     const double dbly = wl_fixed_to_double(fy);
   615     const float x = dblx / window_data->sdlwindow->w;
   616     const float y = dbly / window_data->sdlwindow->h;
   617 
   618     touch_update(id, x, y);
   619     SDL_SendTouchMotion(1, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f);
   620 }
   621 
   622 static void
   623 touch_handler_frame(void *data, struct wl_touch *touch)
   624 {
   625 
   626 }
   627 
   628 static void
   629 touch_handler_cancel(void *data, struct wl_touch *touch)
   630 {
   631 
   632 }
   633 
   634 static const struct wl_touch_listener touch_listener = {
   635     touch_handler_down,
   636     touch_handler_up,
   637     touch_handler_motion,
   638     touch_handler_frame,
   639     touch_handler_cancel,
   640     NULL, /* shape */
   641     NULL, /* orientation */
   642 };
   643 
   644 static void
   645 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
   646                        uint32_t format, int fd, uint32_t size)
   647 {
   648     struct SDL_WaylandInput *input = data;
   649     char *map_str;
   650 
   651     if (!data) {
   652         close(fd);
   653         return;
   654     }
   655 
   656     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
   657         close(fd);
   658         return;
   659     }
   660 
   661     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
   662     if (map_str == MAP_FAILED) {
   663         close(fd);
   664         return;
   665     }
   666 
   667     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
   668                                                 map_str,
   669                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
   670                                                 0);
   671     munmap(map_str, size);
   672     close(fd);
   673 
   674     if (!input->xkb.keymap) {
   675         fprintf(stderr, "failed to compile keymap\n");
   676         return;
   677     }
   678 
   679     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
   680     if (!input->xkb.state) {
   681         fprintf(stderr, "failed to create XKB state\n");
   682         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
   683         input->xkb.keymap = NULL;
   684         return;
   685     }
   686 }
   687 
   688 static void
   689 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
   690                       uint32_t serial, struct wl_surface *surface,
   691                       struct wl_array *keys)
   692 {
   693     struct SDL_WaylandInput *input = data;
   694     SDL_WindowData *window;
   695 
   696     if (!surface) {
   697         /* enter event for a window we've just destroyed */
   698         return;
   699     }
   700 
   701     window = wl_surface_get_user_data(surface);
   702 
   703     if (window) {
   704         input->keyboard_focus = window;
   705         window->keyboard_device = input;
   706         SDL_SetKeyboardFocus(window->sdlwindow);
   707     }
   708 }
   709 
   710 static void
   711 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
   712                       uint32_t serial, struct wl_surface *surface)
   713 {
   714     SDL_SetKeyboardFocus(NULL);
   715 }
   716 
   717 static SDL_bool
   718 keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key)
   719 {
   720     SDL_WindowData *window = input->keyboard_focus;
   721     const xkb_keysym_t *syms;
   722 
   723     if (!window || window->keyboard_device != input || !input->xkb.state) {
   724         return SDL_FALSE;
   725     }
   726 
   727     // TODO can this happen?
   728     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
   729         return SDL_FALSE;
   730     }
   731 
   732     return WAYLAND_xkb_keysym_to_utf8(syms[0], text, 8) > 0;
   733 }
   734 
   735 static void
   736 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
   737                     uint32_t serial, uint32_t time, uint32_t key,
   738                     uint32_t state_w)
   739 {
   740     struct SDL_WaylandInput *input = data;
   741     enum wl_keyboard_key_state state = state_w;
   742     uint32_t scancode = SDL_SCANCODE_UNKNOWN;
   743     char text[8];
   744 
   745     if (key < SDL_arraysize(xfree86_scancode_table2)) {
   746         scancode = xfree86_scancode_table2[key];
   747 
   748         if (scancode != SDL_SCANCODE_UNKNOWN) {
   749             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
   750                                 SDL_PRESSED : SDL_RELEASED, scancode);
   751         }
   752     }
   753 
   754     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
   755         SDL_bool has_text = keyboard_input_get_text(text, input, key);
   756         if (has_text) {
   757             Wayland_data_device_set_serial(input->data_device, serial);
   758             SDL_SendKeyboardText(text);
   759         }
   760         keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text);
   761     } else {
   762         keyboard_repeat_clear(&input->keyboard_repeat);
   763     }
   764 }
   765 
   766 static void
   767 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
   768                           uint32_t serial, uint32_t mods_depressed,
   769                           uint32_t mods_latched, uint32_t mods_locked,
   770                           uint32_t group)
   771 {
   772     struct SDL_WaylandInput *input = data;
   773 
   774     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
   775                           mods_locked, 0, 0, group);
   776 }
   777 
   778 static void
   779 keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
   780                             int32_t rate, int32_t delay)
   781 {
   782     struct SDL_WaylandInput *input = data;
   783     input->keyboard_repeat.repeat_rate = SDL_max(0, SDL_min(rate, 1000));
   784     input->keyboard_repeat.repeat_delay = delay;
   785     input->keyboard_repeat.is_initialized = SDL_TRUE;
   786 }
   787 
   788 static const struct wl_keyboard_listener keyboard_listener = {
   789     keyboard_handle_keymap,
   790     keyboard_handle_enter,
   791     keyboard_handle_leave,
   792     keyboard_handle_key,
   793     keyboard_handle_modifiers,
   794     keyboard_handle_repeat_info,    // Version 4
   795 };
   796 
   797 static void
   798 seat_handle_capabilities(void *data, struct wl_seat *seat,
   799                          enum wl_seat_capability caps)
   800 {
   801     struct SDL_WaylandInput *input = data;
   802 
   803     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
   804         input->pointer = wl_seat_get_pointer(seat);
   805         memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
   806         input->display->pointer = input->pointer;
   807         wl_pointer_set_user_data(input->pointer, input);
   808         wl_pointer_add_listener(input->pointer, &pointer_listener,
   809                                 input);
   810     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
   811         wl_pointer_destroy(input->pointer);
   812         input->pointer = NULL;
   813         input->display->pointer = NULL;
   814     }
   815 
   816     if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
   817         SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
   818         input->touch = wl_seat_get_touch(seat);
   819         wl_touch_set_user_data(input->touch, input);
   820         wl_touch_add_listener(input->touch, &touch_listener,
   821                                  input);
   822     } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
   823         SDL_DelTouch(1);
   824         wl_touch_destroy(input->touch);
   825         input->touch = NULL;
   826     }
   827 
   828     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
   829         input->keyboard = wl_seat_get_keyboard(seat);
   830         wl_keyboard_set_user_data(input->keyboard, input);
   831         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
   832                                  input);
   833     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
   834         wl_keyboard_destroy(input->keyboard);
   835         input->keyboard = NULL;
   836     }
   837 }
   838 
   839 static void
   840 seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
   841 {
   842     /* unimplemented */
   843 }
   844 
   845 static const struct wl_seat_listener seat_listener = {
   846     seat_handle_capabilities,
   847     seat_handle_name,           // Version 2
   848 };
   849 
   850 static void
   851 data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
   852                           const char *mime_type)
   853 {
   854 }
   855 
   856 static void
   857 data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
   858                         const char *mime_type, int32_t fd)
   859 {
   860     Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
   861 }
   862 
   863 static void
   864 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
   865 {
   866     Wayland_data_source_destroy(data);
   867 }
   868 
   869 static void
   870 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
   871 {
   872 }
   873 
   874 static void
   875 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
   876 {
   877 }
   878 
   879 static void
   880 data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
   881                           uint32_t dnd_action)
   882 {
   883 }
   884 
   885 static const struct wl_data_source_listener data_source_listener = {
   886     data_source_handle_target,
   887     data_source_handle_send,
   888     data_source_handle_cancelled,
   889     data_source_handle_dnd_drop_performed, // Version 3
   890     data_source_handle_dnd_finished,       // Version 3
   891     data_source_handle_action,             // Version 3
   892 };
   893 
   894 SDL_WaylandDataSource*
   895 Wayland_data_source_create(_THIS)
   896 {
   897     SDL_WaylandDataSource *data_source = NULL;
   898     SDL_VideoData *driver_data = NULL;
   899     struct wl_data_source *id = NULL;
   900 
   901     if (_this == NULL || _this->driverdata == NULL) {
   902         SDL_SetError("Video driver uninitialized");
   903     } else {
   904         driver_data = _this->driverdata;
   905 
   906         if (driver_data->data_device_manager != NULL) {
   907             id = wl_data_device_manager_create_data_source(
   908                      driver_data->data_device_manager);
   909         }
   910 
   911         if (id == NULL) {
   912             SDL_SetError("Wayland unable to create data source");
   913         } else {
   914             data_source = SDL_calloc(1, sizeof *data_source);
   915             if (data_source == NULL) {
   916                 SDL_OutOfMemory();
   917                 wl_data_source_destroy(id);
   918             } else {
   919                 WAYLAND_wl_list_init(&(data_source->mimes));
   920                 data_source->source = id;
   921                 wl_data_source_set_user_data(id, data_source);
   922                 wl_data_source_add_listener(id, &data_source_listener,
   923                                             data_source);
   924             }
   925         }
   926     }
   927     return data_source;
   928 }
   929 
   930 static void
   931 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
   932                         const char *mime_type)
   933 {
   934     SDL_WaylandDataOffer *offer = data;
   935     Wayland_data_offer_add_mime(offer, mime_type);
   936 }
   937 
   938 static void
   939 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
   940                                  uint32_t source_actions)
   941 {
   942 }
   943 
   944 static void
   945 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
   946                           uint32_t dnd_action)
   947 {
   948 }
   949 
   950 static const struct wl_data_offer_listener data_offer_listener = {
   951     data_offer_handle_offer,
   952     data_offer_handle_source_actions, // Version 3
   953     data_offer_handle_actions,        // Version 3
   954 };
   955 
   956 static void
   957 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
   958                               struct wl_data_offer *id)
   959 {
   960     SDL_WaylandDataOffer *data_offer = NULL;
   961 
   962     data_offer = SDL_calloc(1, sizeof *data_offer);
   963     if (data_offer == NULL) {
   964         SDL_OutOfMemory();
   965     } else {
   966         data_offer->offer = id;
   967         data_offer->data_device = data;
   968         WAYLAND_wl_list_init(&(data_offer->mimes));
   969         wl_data_offer_set_user_data(id, data_offer);
   970         wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
   971     }
   972 }
   973 
   974 static void
   975 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
   976                          uint32_t serial, struct wl_surface *surface,
   977                          wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
   978 {
   979     SDL_WaylandDataDevice *data_device = data;
   980     SDL_bool has_mime = SDL_FALSE;
   981     uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
   982 
   983     data_device->drag_serial = serial;
   984 
   985     if (id != NULL) {
   986         data_device->drag_offer = wl_data_offer_get_user_data(id);
   987 
   988         /* TODO: SDL Support more mime types */
   989         has_mime = Wayland_data_offer_has_mime(
   990             data_device->drag_offer, FILE_MIME);
   991 
   992         /* If drag_mime is NULL this will decline the offer */
   993         wl_data_offer_accept(id, serial,
   994                              (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
   995 
   996         /* SDL only supports "copy" style drag and drop */
   997         if (has_mime == SDL_TRUE) {
   998             dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
   999         }
  1000         if (wl_data_offer_get_version(data_device->drag_offer->offer) >= 3) {
  1001             wl_data_offer_set_actions(data_device->drag_offer->offer,
  1002                                       dnd_action, dnd_action);
  1003         }
  1004     }
  1005 }
  1006 
  1007 static void
  1008 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
  1009 {
  1010     SDL_WaylandDataDevice *data_device = data;
  1011     SDL_WaylandDataOffer *offer = NULL;
  1012 
  1013     if (data_device->selection_offer != NULL) {
  1014         data_device->selection_offer = NULL;
  1015         Wayland_data_offer_destroy(offer);
  1016     }
  1017 }
  1018 
  1019 static void
  1020 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
  1021                           uint32_t time, wl_fixed_t x, wl_fixed_t y)
  1022 {
  1023 }
  1024 
  1025 static void
  1026 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
  1027 {
  1028     SDL_WaylandDataDevice *data_device = data;
  1029     void *buffer = NULL;
  1030     size_t length = 0;
  1031 
  1032     const char *current_uri = NULL;
  1033     const char *last_char = NULL;
  1034     char *current_char = NULL;
  1035 
  1036     if (data_device->drag_offer != NULL) {
  1037         /* TODO: SDL Support more mime types */
  1038         buffer = Wayland_data_offer_receive(data_device->drag_offer,
  1039                                             &length, FILE_MIME, SDL_FALSE);
  1040 
  1041         /* uri-list */
  1042         current_uri = (const char *)buffer;
  1043         last_char = (const char *)buffer + length;
  1044         for (current_char = buffer; current_char < last_char; ++current_char) {
  1045             if (*current_char == '\n' || *current_char == 0) {
  1046                 if (*current_uri != 0 && *current_uri != '#') {
  1047                     *current_char = 0;
  1048                     SDL_SendDropFile(NULL, current_uri);
  1049                 }
  1050                 current_uri = (const char *)current_char + 1;
  1051             }
  1052         }
  1053 
  1054         SDL_free(buffer);
  1055     }
  1056 }
  1057 
  1058 static void
  1059 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
  1060                              struct wl_data_offer *id)
  1061 {
  1062     SDL_WaylandDataDevice *data_device = data;
  1063     SDL_WaylandDataOffer *offer = NULL;
  1064 
  1065     if (id != NULL) {
  1066         offer = wl_data_offer_get_user_data(id);
  1067     }
  1068 
  1069     if (data_device->selection_offer != offer) {
  1070         Wayland_data_offer_destroy(data_device->selection_offer);
  1071         data_device->selection_offer = offer;
  1072     }
  1073 
  1074     SDL_SendClipboardUpdate();
  1075 }
  1076 
  1077 static const struct wl_data_device_listener data_device_listener = {
  1078     data_device_handle_data_offer,
  1079     data_device_handle_enter,
  1080     data_device_handle_leave,
  1081     data_device_handle_motion,
  1082     data_device_handle_drop,
  1083     data_device_handle_selection
  1084 };
  1085 
  1086 void
  1087 Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
  1088 {
  1089     struct SDL_WaylandInput *input;
  1090     SDL_WaylandDataDevice *data_device = NULL;
  1091 
  1092     input = SDL_calloc(1, sizeof *input);
  1093     if (input == NULL)
  1094         return;
  1095 
  1096     input->display = d;
  1097     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
  1098     input->sx_w = wl_fixed_from_int(0);
  1099     input->sy_w = wl_fixed_from_int(0);
  1100     d->input = input;
  1101 
  1102     if (d->data_device_manager != NULL) {
  1103         data_device = SDL_calloc(1, sizeof *data_device);
  1104         if (data_device == NULL) {
  1105             return;
  1106         }
  1107 
  1108         data_device->data_device = wl_data_device_manager_get_data_device(
  1109             d->data_device_manager, input->seat
  1110         );
  1111         data_device->video_data = d;
  1112 
  1113         if (data_device->data_device == NULL) {
  1114             SDL_free(data_device);
  1115         } else {
  1116             wl_data_device_set_user_data(data_device->data_device, data_device);
  1117             wl_data_device_add_listener(data_device->data_device,
  1118                                         &data_device_listener, data_device);
  1119             input->data_device = data_device;
  1120         }
  1121     }
  1122 
  1123     wl_seat_add_listener(input->seat, &seat_listener, input);
  1124     wl_seat_set_user_data(input->seat, input);
  1125 
  1126     WAYLAND_wl_display_flush(d->display);
  1127 }
  1128 
  1129 void Wayland_display_destroy_input(SDL_VideoData *d)
  1130 {
  1131     struct SDL_WaylandInput *input = d->input;
  1132 
  1133     if (!input)
  1134         return;
  1135 
  1136     if (input->data_device != NULL) {
  1137         Wayland_data_device_clear_selection(input->data_device);
  1138         if (input->data_device->selection_offer != NULL) {
  1139             Wayland_data_offer_destroy(input->data_device->selection_offer);
  1140         }
  1141         if (input->data_device->drag_offer != NULL) {
  1142             Wayland_data_offer_destroy(input->data_device->drag_offer);
  1143         }
  1144         if (input->data_device->data_device != NULL) {
  1145             wl_data_device_release(input->data_device->data_device);
  1146         }
  1147         SDL_free(input->data_device);
  1148     }
  1149 
  1150     if (input->keyboard)
  1151         wl_keyboard_destroy(input->keyboard);
  1152 
  1153     if (input->pointer)
  1154         wl_pointer_destroy(input->pointer);
  1155 
  1156     if (input->touch) {
  1157         SDL_DelTouch(1);
  1158         wl_touch_destroy(input->touch);
  1159     }
  1160 
  1161     if (input->seat)
  1162         wl_seat_destroy(input->seat);
  1163 
  1164     if (input->xkb.state)
  1165         WAYLAND_xkb_state_unref(input->xkb.state);
  1166 
  1167     if (input->xkb.keymap)
  1168         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
  1169 
  1170     SDL_free(input);
  1171     d->input = NULL;
  1172 }
  1173 
  1174 SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
  1175 {
  1176     if (input == NULL) {
  1177         return NULL;
  1178     }
  1179 
  1180     return input->data_device;
  1181 }
  1182 
  1183 /* !!! FIXME: just merge these into display_handle_global(). */
  1184 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
  1185 {
  1186     d->relative_pointer_manager =
  1187         wl_registry_bind(d->registry, id,
  1188                          &zwp_relative_pointer_manager_v1_interface, 1);
  1189 }
  1190 
  1191 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
  1192 {
  1193     if (d->relative_pointer_manager)
  1194         zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
  1195 }
  1196 
  1197 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
  1198 {
  1199     d->pointer_constraints =
  1200         wl_registry_bind(d->registry, id,
  1201                          &zwp_pointer_constraints_v1_interface, 1);
  1202 }
  1203 
  1204 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
  1205 {
  1206     if (d->pointer_constraints)
  1207         zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
  1208 }
  1209 
  1210 static void
  1211 relative_pointer_handle_relative_motion(void *data,
  1212                                         struct zwp_relative_pointer_v1 *pointer,
  1213                                         uint32_t time_hi,
  1214                                         uint32_t time_lo,
  1215                                         wl_fixed_t dx_w,
  1216                                         wl_fixed_t dy_w,
  1217                                         wl_fixed_t dx_unaccel_w,
  1218                                         wl_fixed_t dy_unaccel_w)
  1219 {
  1220     struct SDL_WaylandInput *input = data;
  1221     SDL_VideoData *d = input->display;
  1222     SDL_WindowData *window = input->pointer_focus;
  1223     double dx_unaccel;
  1224     double dy_unaccel;
  1225     double dx;
  1226     double dy;
  1227 
  1228     dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
  1229     dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
  1230 
  1231     /* Add left over fraction from last event. */
  1232     dx_unaccel += input->dx_frac;
  1233     dy_unaccel += input->dy_frac;
  1234 
  1235     input->dx_frac = modf(dx_unaccel, &dx);
  1236     input->dy_frac = modf(dy_unaccel, &dy);
  1237 
  1238     if (input->pointer_focus && d->relative_mouse_mode) {
  1239         SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
  1240     }
  1241 }
  1242 
  1243 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
  1244     relative_pointer_handle_relative_motion,
  1245 };
  1246 
  1247 static void
  1248 locked_pointer_locked(void *data,
  1249                       struct zwp_locked_pointer_v1 *locked_pointer)
  1250 {
  1251 }
  1252 
  1253 static void
  1254 locked_pointer_unlocked(void *data,
  1255                         struct zwp_locked_pointer_v1 *locked_pointer)
  1256 {
  1257 }
  1258 
  1259 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
  1260     locked_pointer_locked,
  1261     locked_pointer_unlocked,
  1262 };
  1263 
  1264 static void
  1265 lock_pointer_to_window(SDL_Window *window,
  1266                        struct SDL_WaylandInput *input)
  1267 {
  1268     SDL_WindowData *w = window->driverdata;
  1269     SDL_VideoData *d = input->display;
  1270     struct zwp_locked_pointer_v1 *locked_pointer;
  1271 
  1272     if (w->locked_pointer)
  1273         return;
  1274 
  1275     locked_pointer =
  1276         zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
  1277                                                 w->surface,
  1278                                                 input->pointer,
  1279                                                 NULL,
  1280                                                 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
  1281     zwp_locked_pointer_v1_add_listener(locked_pointer,
  1282                                        &locked_pointer_listener,
  1283                                        window);
  1284 
  1285     w->locked_pointer = locked_pointer;
  1286 }
  1287 
  1288 static void pointer_confine_destroy(struct SDL_WaylandInput *input)
  1289 {
  1290     if (input->confined_pointer) {
  1291         zwp_confined_pointer_v1_destroy(input->confined_pointer);
  1292         input->confined_pointer = NULL;
  1293     }
  1294 }
  1295 
  1296 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
  1297 {
  1298     SDL_VideoDevice *vd = SDL_GetVideoDevice();
  1299     SDL_VideoData *d = input->display;
  1300     SDL_Window *window;
  1301     struct zwp_relative_pointer_v1 *relative_pointer;
  1302 
  1303     if (!d->relative_pointer_manager)
  1304         return -1;
  1305 
  1306     if (!d->pointer_constraints)
  1307         return -1;
  1308 
  1309     if (!input->pointer)
  1310         return -1;
  1311 
  1312     /* If we have a pointer confine active, we must destroy it here because
  1313      * creating a locked pointer otherwise would be a protocol error. */
  1314     pointer_confine_destroy(input);
  1315 
  1316     if (!input->relative_pointer) {
  1317         relative_pointer =
  1318             zwp_relative_pointer_manager_v1_get_relative_pointer(
  1319                 d->relative_pointer_manager,
  1320                 input->pointer);
  1321         zwp_relative_pointer_v1_add_listener(relative_pointer,
  1322                                              &relative_pointer_listener,
  1323                                              input);
  1324         input->relative_pointer = relative_pointer;
  1325     }
  1326 
  1327     for (window = vd->windows; window; window = window->next)
  1328         lock_pointer_to_window(window, input);
  1329 
  1330     d->relative_mouse_mode = 1;
  1331 
  1332     return 0;
  1333 }
  1334 
  1335 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
  1336 {
  1337     SDL_VideoDevice *vd = SDL_GetVideoDevice();
  1338     SDL_VideoData *d = input->display;
  1339     SDL_Window *window;
  1340     SDL_WindowData *w;
  1341 
  1342     for (window = vd->windows; window; window = window->next) {
  1343         w = window->driverdata;
  1344         if (w->locked_pointer)
  1345             zwp_locked_pointer_v1_destroy(w->locked_pointer);
  1346         w->locked_pointer = NULL;
  1347     }
  1348 
  1349     zwp_relative_pointer_v1_destroy(input->relative_pointer);
  1350     input->relative_pointer = NULL;
  1351 
  1352     d->relative_mouse_mode = 0;
  1353 
  1354     if (input->confined_pointer_window)
  1355         Wayland_input_confine_pointer(input->confined_pointer_window, input);
  1356 
  1357     return 0;
  1358 }
  1359 
  1360 static void
  1361 confined_pointer_confined(void *data,
  1362                           struct zwp_confined_pointer_v1 *confined_pointer)
  1363 {
  1364 }
  1365 
  1366 static void
  1367 confined_pointer_unconfined(void *data,
  1368                             struct zwp_confined_pointer_v1 *confined_pointer)
  1369 {
  1370 }
  1371 
  1372 static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
  1373     confined_pointer_confined,
  1374     confined_pointer_unconfined,
  1375 };
  1376 
  1377 int Wayland_input_confine_pointer(SDL_Window *window, struct SDL_WaylandInput *input)
  1378 {
  1379     SDL_WindowData *w = window->driverdata;
  1380     SDL_VideoData *d = input->display;
  1381     struct zwp_confined_pointer_v1 *confined_pointer;
  1382 
  1383     if (!d->pointer_constraints)
  1384         return -1;
  1385 
  1386     if (!input->pointer)
  1387         return -1;
  1388 
  1389     /* A confine may already be active, in which case we should destroy it and
  1390      * create a new one. */
  1391     if (input->confined_pointer)
  1392         Wayland_input_unconfine_pointer(input);
  1393 
  1394     input->confined_pointer_window = window;
  1395 
  1396     /* We cannot create a confine if the pointer is already locked. Defer until
  1397      * the pointer is unlocked. */
  1398     if (d->relative_mouse_mode)
  1399         return 0;
  1400 
  1401     confined_pointer =
  1402         zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
  1403                                                    w->surface,
  1404                                                    input->pointer,
  1405                                                    NULL,
  1406                                                    ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
  1407     zwp_confined_pointer_v1_add_listener(confined_pointer,
  1408                                          &confined_pointer_listener,
  1409                                          window);
  1410 
  1411     input->confined_pointer = confined_pointer;
  1412     return 0;
  1413 }
  1414 
  1415 int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input)
  1416 {
  1417     pointer_confine_destroy(input);
  1418     input->confined_pointer_window = NULL;
  1419     return 0;
  1420 }
  1421 
  1422 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
  1423 
  1424 /* vi: set ts=4 sw=4 expandtab: */