src/video/wayland/SDL_waylandevents.c
author Ryan C. Gordon
Tue, 07 Apr 2020 13:30:46 -0400
changeset 13701 3cc182fa6110
parent 13696 ea20a7434b98
child 13805 4709c1dfeabb
permissions -rw-r--r--
wayland: Support wayland compositors with wl_seat version < 5 (thanks, Nia!).

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