sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_waylandevents.c (43985B)


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