wayland: Add support for relative mouse mode, by Jonas Ådahl <jadahl@gmail.com>
authorSam Lantinga <slouken@libsdl.org>
Thu, 01 Sep 2016 01:26:56 -0700
changeset 10304ee83e0b4a36f
parent 10303 b326f93e1bc5
child 10305 a289f7ea213b
wayland: Add support for relative mouse mode, by Jonas Ådahl <jadahl@gmail.com>

Generate the C protocol files from the protocol XML files installed by
wayland-protocols, and use them to implement support for relative pointer
motions and pointer locking.

Note that at the time, the protocol is unstable and may change in the future.
Any future breaking changes will, however, fail gracefully and result in no
regressions compared to before this patch.
configure
configure.in
src/video/wayland/SDL_waylandevents.c
src/video/wayland/SDL_waylandevents_c.h
src/video/wayland/SDL_waylandmouse.c
src/video/wayland/SDL_waylandvideo.c
src/video/wayland/SDL_waylandvideo.h
src/video/wayland/SDL_waylandwindow.c
src/video/wayland/SDL_waylandwindow.h
     1.1 --- a/configure	Thu Jun 23 18:39:05 2016 +0800
     1.2 +++ b/configure	Thu Sep 01 01:26:56 2016 -0700
     1.3 @@ -18807,11 +18807,12 @@
     1.4          if  test x$PKG_CONFIG != xno && \
     1.5              test x$video_opengl_egl = xyes && \
     1.6              test x$video_opengles_v2 = xyes; then
     1.7 -            if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-egl wayland-cursor egl xkbcommon ; then
     1.8 +            if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-protocols wayland-egl wayland-cursor egl xkbcommon ; then
     1.9                  WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor xkbcommon`
    1.10                  WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor xkbcommon`
    1.11                  WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`
    1.12                  WAYLAND_CORE_PROTOCOL_DIR=`$PKG_CONFIG --variable=pkgdatadir wayland-client`
    1.13 +                WAYLAND_PROTOCOLS_DIR=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`
    1.14                  video_wayland=yes
    1.15              fi
    1.16          fi
    1.17 @@ -18827,6 +18828,9 @@
    1.18  $as_echo "#define SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH 1" >>confdefs.h
    1.19  
    1.20              fi
    1.21 +
    1.22 +            WAYLAND_PROTOCOLS_UNSTABLE="relative-pointer-unstable-v1 pointer-constraints-unstable-v1"
    1.23 +
    1.24              SOURCES="$SOURCES $srcdir/src/video/wayland/*.c"
    1.25              EXTRA_CFLAGS="$EXTRA_CFLAGS $WAYLAND_CFLAGS -I\$(gen)"
    1.26              # Check whether --enable-wayland-shared was given.
    1.27 @@ -23736,8 +23740,12 @@
    1.28  if test x$video_wayland = xyes; then
    1.29      WAYLAND_CORE_PROTOCOL_SOURCE='$(gen)/wayland-protocol.c'
    1.30      WAYLAND_CORE_PROTOCOL_HEADER='$(gen)/wayland-client-protocol.h'
    1.31 -    GEN_SOURCES="$GEN_SOURCES $WAYLAND_CORE_PROTOCOL_SOURCE"
    1.32 -    GEN_HEADERS="$GEN_HEADERS $WAYLAND_CORE_PROTOCOL_HEADER"
    1.33 +    WAYLAND_PROTOCOLS_UNSTABLE_SOURCES=`echo $WAYLAND_PROTOCOLS_UNSTABLE |\
    1.34 +        sed 's,[^ ]\+,\\$(gen)/&-protocol.c,g'`
    1.35 +    WAYLAND_PROTOCOLS_UNSTABLE_HEADERS=`echo $WAYLAND_PROTOCOLS_UNSTABLE |\
    1.36 +        sed 's,[^ ]\+,\\$(gen)/&-client-protocol.h,g'`
    1.37 +    GEN_SOURCES="$GEN_SOURCES $WAYLAND_CORE_PROTOCOL_SOURCE $WAYLAND_PROTOCOLS_UNSTABLE_SOURCES"
    1.38 +    GEN_HEADERS="$GEN_HEADERS $WAYLAND_CORE_PROTOCOL_HEADER $WAYLAND_PROTOCOLS_UNSTABLE_HEADERS"
    1.39  
    1.40      WAYLAND_CORE_PROTOCOL_SOURCE_DEPENDS="
    1.41  $WAYLAND_CORE_PROTOCOL_SOURCE: $WAYLAND_CORE_PROTOCOL_DIR/wayland.xml
    1.42 @@ -23753,10 +23761,30 @@
    1.43  \$(objects)/`echo $WAYLAND_CORE_PROTOCOL_SOURCE | sed 's/\$(gen)\/\(.*\).c$/\1.lo/'`: $WAYLAND_CORE_PROTOCOL_SOURCE
    1.44  	\$(RUN_CMD_CC)\$(LIBTOOL) --tag=CC --mode=compile \$(CC) \$(CFLAGS) \$(EXTRA_CFLAGS) $DEPENDENCY_TRACKING_OPTIONS -c \$< -o \$@"
    1.45  
    1.46 +    WAYLAND_PROTOCOLS_CLIENT_HEADER_UNSTABLE_DEPENDS=`for p in $WAYLAND_PROTOCOLS_UNSTABLE;\
    1.47 +        do echo ; echo \$p | sed\
    1.48 +        "s,^\\([a-z\\-]\\+\\)-unstable-\\(v[0-9]\+\\)\$,\\$(gen)/&-client-protocol.h: $WAYLAND_PROTOCOLS_DIR/unstable/\1/&.xml\\\\
    1.49 +	\\$(SHELL) \\$(auxdir)/mkinstalldirs \\$(gen)\\\\
    1.50 +	\\$(RUN_CMD_GEN)\\$(WAYLAND_SCANNER) client-header \\$< \\$@," ; done`
    1.51 +
    1.52 +    WAYLAND_PROTOCOLS_CODE_UNSTABLE_DEPENDS=`for p in $WAYLAND_PROTOCOLS_UNSTABLE;\
    1.53 +        do echo ; echo \$p | sed\
    1.54 +        "s,^\\([a-z\\-]\\+\\)-unstable-\\(v[0-9]\+\\)\$,\\$(gen)/&-protocol.c: $WAYLAND_PROTOCOLS_DIR/unstable/\1/&.xml\\\\
    1.55 +	\\$(SHELL) \\$(auxdir)/mkinstalldirs \\$(gen)\\\\
    1.56 +	\\$(RUN_CMD_GEN)\\$(WAYLAND_SCANNER) code \\$< \\$@," ; done`
    1.57 +
    1.58 +    WAYLAND_PROTOCOLS_OBJECTS_UNSTABLE=`for p in $WAYLAND_PROTOCOLS_UNSTABLE;\
    1.59 +        do echo ; echo \$p | sed\
    1.60 +        "s,^\\([a-z\\-]\\+\\)-unstable-\\(v[0-9]\+\\)\$,\\\$(objects)/&-protocol.lo: \\$(gen)/&-protocol.c \\$(gen)/&-client-protocol.h\\\\
    1.61 +	\\$(RUN_CMD_CC)\\$(LIBTOOL) --tag=CC --mode=compile \\$(CC) \\$(CFLAGS) \\$(EXTRA_CFLAGS) $DEPENDENCY_TRACKING_OPTIONS -c \\$< -o \\$@," ; done`
    1.62 +
    1.63      WAYLAND_PROTOCOLS_DEPENDS="
    1.64  $WAYLAND_CORE_PROTOCOL_SOURCE_DEPENDS
    1.65  $WAYLAND_CORE_PROTOCOL_HEADER_DEPENDS
    1.66  $WAYLAND_CORE_PROTOCOL_OBJECT
    1.67 +$WAYLAND_PROTOCOLS_CLIENT_HEADER_UNSTABLE_DEPENDS
    1.68 +$WAYLAND_PROTOCOLS_CODE_UNSTABLE_DEPENDS
    1.69 +$WAYLAND_PROTOCOLS_OBJECTS_UNSTABLE
    1.70  "
    1.71  fi
    1.72  
     2.1 --- a/configure.in	Thu Jun 23 18:39:05 2016 +0800
     2.2 +++ b/configure.in	Thu Sep 01 01:26:56 2016 -0700
     2.3 @@ -1201,11 +1201,12 @@
     2.4          if  test x$PKG_CONFIG != xno && \
     2.5              test x$video_opengl_egl = xyes && \
     2.6              test x$video_opengles_v2 = xyes; then
     2.7 -            if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-egl wayland-cursor egl xkbcommon ; then
     2.8 +            if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-protocols wayland-egl wayland-cursor egl xkbcommon ; then
     2.9                  WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor xkbcommon`
    2.10                  WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor xkbcommon`
    2.11                  WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`
    2.12                  WAYLAND_CORE_PROTOCOL_DIR=`$PKG_CONFIG --variable=pkgdatadir wayland-client`
    2.13 +                WAYLAND_PROTOCOLS_DIR=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`
    2.14                  video_wayland=yes
    2.15              fi
    2.16          fi
    2.17 @@ -1216,6 +1217,9 @@
    2.18              if test x$enable_video_wayland_qt_touch = xyes; then
    2.19                  AC_DEFINE(SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH, 1, [ ])
    2.20              fi
    2.21 +
    2.22 +            WAYLAND_PROTOCOLS_UNSTABLE="relative-pointer-unstable-v1 pointer-constraints-unstable-v1"
    2.23 +
    2.24              SOURCES="$SOURCES $srcdir/src/video/wayland/*.c"
    2.25              EXTRA_CFLAGS="$EXTRA_CFLAGS $WAYLAND_CFLAGS -I\$(gen)"
    2.26              AC_ARG_ENABLE(wayland-shared,
    2.27 @@ -3486,8 +3490,12 @@
    2.28  if test x$video_wayland = xyes; then
    2.29      WAYLAND_CORE_PROTOCOL_SOURCE='$(gen)/wayland-protocol.c'
    2.30      WAYLAND_CORE_PROTOCOL_HEADER='$(gen)/wayland-client-protocol.h'
    2.31 -    GEN_SOURCES="$GEN_SOURCES $WAYLAND_CORE_PROTOCOL_SOURCE"
    2.32 -    GEN_HEADERS="$GEN_HEADERS $WAYLAND_CORE_PROTOCOL_HEADER"
    2.33 +    WAYLAND_PROTOCOLS_UNSTABLE_SOURCES=`echo $WAYLAND_PROTOCOLS_UNSTABLE |\
    2.34 +        sed 's,[[^ ]]\+,\\$(gen)/&-protocol.c,g'`
    2.35 +    WAYLAND_PROTOCOLS_UNSTABLE_HEADERS=`echo $WAYLAND_PROTOCOLS_UNSTABLE |\
    2.36 +        sed 's,[[^ ]]\+,\\$(gen)/&-client-protocol.h,g'`
    2.37 +    GEN_SOURCES="$GEN_SOURCES $WAYLAND_CORE_PROTOCOL_SOURCE $WAYLAND_PROTOCOLS_UNSTABLE_SOURCES"
    2.38 +    GEN_HEADERS="$GEN_HEADERS $WAYLAND_CORE_PROTOCOL_HEADER $WAYLAND_PROTOCOLS_UNSTABLE_HEADERS"
    2.39  
    2.40      WAYLAND_CORE_PROTOCOL_SOURCE_DEPENDS="
    2.41  $WAYLAND_CORE_PROTOCOL_SOURCE: $WAYLAND_CORE_PROTOCOL_DIR/wayland.xml
    2.42 @@ -3503,10 +3511,30 @@
    2.43  \$(objects)/`echo $WAYLAND_CORE_PROTOCOL_SOURCE | sed 's/\$(gen)\/\(.*\).c$/\1.lo/'`: $WAYLAND_CORE_PROTOCOL_SOURCE
    2.44  	\$(RUN_CMD_CC)\$(LIBTOOL) --tag=CC --mode=compile \$(CC) \$(CFLAGS) \$(EXTRA_CFLAGS) $DEPENDENCY_TRACKING_OPTIONS -c \$< -o \$@"
    2.45  
    2.46 +    WAYLAND_PROTOCOLS_CLIENT_HEADER_UNSTABLE_DEPENDS=`for p in $WAYLAND_PROTOCOLS_UNSTABLE;\
    2.47 +        do echo ; echo \$p | sed\
    2.48 +        "s,^\\([[a-z\\-]]\\+\\)-unstable-\\(v[[0-9]]\+\\)\$,\\$(gen)/&-client-protocol.h: $WAYLAND_PROTOCOLS_DIR/unstable/\1/&.xml\\\\
    2.49 +	\\$(SHELL) \\$(auxdir)/mkinstalldirs \\$(gen)\\\\
    2.50 +	\\$(RUN_CMD_GEN)\\$(WAYLAND_SCANNER) client-header \\$< \\$@," ; done`
    2.51 +
    2.52 +    WAYLAND_PROTOCOLS_CODE_UNSTABLE_DEPENDS=`for p in $WAYLAND_PROTOCOLS_UNSTABLE;\
    2.53 +        do echo ; echo \$p | sed\
    2.54 +        "s,^\\([[a-z\\-]]\\+\\)-unstable-\\(v[[0-9]]\+\\)\$,\\$(gen)/&-protocol.c: $WAYLAND_PROTOCOLS_DIR/unstable/\1/&.xml\\\\
    2.55 +	\\$(SHELL) \\$(auxdir)/mkinstalldirs \\$(gen)\\\\
    2.56 +	\\$(RUN_CMD_GEN)\\$(WAYLAND_SCANNER) code \\$< \\$@," ; done`
    2.57 +
    2.58 +    WAYLAND_PROTOCOLS_OBJECTS_UNSTABLE=`for p in $WAYLAND_PROTOCOLS_UNSTABLE;\
    2.59 +        do echo ; echo \$p | sed\
    2.60 +        "s,^\\([[a-z\\-]]\\+\\)-unstable-\\(v[[0-9]]\+\\)\$,\\\$(objects)/&-protocol.lo: \\$(gen)/&-protocol.c \\$(gen)/&-client-protocol.h\\\\
    2.61 +	\\$(RUN_CMD_CC)\\$(LIBTOOL) --tag=CC --mode=compile \\$(CC) \\$(CFLAGS) \\$(EXTRA_CFLAGS) $DEPENDENCY_TRACKING_OPTIONS -c \\$< -o \\$@," ; done`
    2.62 +
    2.63      WAYLAND_PROTOCOLS_DEPENDS="
    2.64  $WAYLAND_CORE_PROTOCOL_SOURCE_DEPENDS
    2.65  $WAYLAND_CORE_PROTOCOL_HEADER_DEPENDS
    2.66  $WAYLAND_CORE_PROTOCOL_OBJECT
    2.67 +$WAYLAND_PROTOCOLS_CLIENT_HEADER_UNSTABLE_DEPENDS
    2.68 +$WAYLAND_PROTOCOLS_CODE_UNSTABLE_DEPENDS
    2.69 +$WAYLAND_PROTOCOLS_OBJECTS_UNSTABLE
    2.70  "
    2.71  fi
    2.72  
     3.1 --- a/src/video/wayland/SDL_waylandevents.c	Thu Jun 23 18:39:05 2016 +0800
     3.2 +++ b/src/video/wayland/SDL_waylandevents.c	Thu Sep 01 01:26:56 2016 -0700
     3.3 @@ -25,6 +25,7 @@
     3.4  
     3.5  #include "SDL_stdinc.h"
     3.6  #include "SDL_assert.h"
     3.7 +#include "SDL_log.h"
     3.8  
     3.9  #include "../../events/SDL_sysevents.h"
    3.10  #include "../../events/SDL_events_c.h"
    3.11 @@ -36,6 +37,9 @@
    3.12  
    3.13  #include "SDL_waylanddyn.h"
    3.14  
    3.15 +#include "pointer-constraints-unstable-v1-client-protocol.h"
    3.16 +#include "relative-pointer-unstable-v1-client-protocol.h"
    3.17 +
    3.18  #include <linux/input.h>
    3.19  #include <sys/select.h>
    3.20  #include <sys/mman.h>
    3.21 @@ -48,13 +52,17 @@
    3.22      struct wl_seat *seat;
    3.23      struct wl_pointer *pointer;
    3.24      struct wl_keyboard *keyboard;
    3.25 +    struct zwp_relative_pointer_v1 *relative_pointer;
    3.26      SDL_WindowData *pointer_focus;
    3.27      SDL_WindowData *keyboard_focus;
    3.28  
    3.29      /* Last motion location */
    3.30      wl_fixed_t sx_w;
    3.31      wl_fixed_t sy_w;
    3.32 -    
    3.33 +
    3.34 +    double dx_frac;
    3.35 +    double dy_frac;
    3.36 +
    3.37      struct {
    3.38          struct xkb_keymap *keymap;
    3.39          struct xkb_state *state;
    3.40 @@ -170,10 +178,9 @@
    3.41  }
    3.42  
    3.43  static void
    3.44 -pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
    3.45 -                      uint32_t time, uint32_t button, uint32_t state_w)
    3.46 +pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
    3.47 +                             uint32_t time, uint32_t button, uint32_t state_w)
    3.48  {
    3.49 -    struct SDL_WaylandInput *input = data;
    3.50      SDL_WindowData *window = input->pointer_focus;
    3.51      enum wl_pointer_button_state state = state_w;
    3.52      uint32_t sdl_button;
    3.53 @@ -182,7 +189,7 @@
    3.54          switch (button) {
    3.55              case BTN_LEFT:
    3.56                  sdl_button = SDL_BUTTON_LEFT;
    3.57 -                if (ProcessHitTest(data, serial)) {
    3.58 +                if (ProcessHitTest(input, serial)) {
    3.59                      return;  /* don't pass this event on to app. */
    3.60                  }
    3.61                  break;
    3.62 @@ -208,10 +215,18 @@
    3.63  }
    3.64  
    3.65  static void
    3.66 -pointer_handle_axis(void *data, struct wl_pointer *pointer,
    3.67 -                    uint32_t time, uint32_t axis, wl_fixed_t value)
    3.68 +pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
    3.69 +                      uint32_t time, uint32_t button, uint32_t state_w)
    3.70  {
    3.71      struct SDL_WaylandInput *input = data;
    3.72 +
    3.73 +    pointer_handle_button_common(input, serial, time, button, state_w);
    3.74 +}
    3.75 +
    3.76 +static void
    3.77 +pointer_handle_axis_common(struct SDL_WaylandInput *input,
    3.78 +                           uint32_t time, uint32_t axis, wl_fixed_t value)
    3.79 +{
    3.80      SDL_WindowData *window = input->pointer_focus;
    3.81      enum wl_pointer_axis a = axis;
    3.82      int x, y;
    3.83 @@ -234,6 +249,15 @@
    3.84      }
    3.85  }
    3.86  
    3.87 +static void
    3.88 +pointer_handle_axis(void *data, struct wl_pointer *pointer,
    3.89 +                    uint32_t time, uint32_t axis, wl_fixed_t value)
    3.90 +{
    3.91 +    struct SDL_WaylandInput *input = data;
    3.92 +
    3.93 +    pointer_handle_axis_common(input, time, axis, value);
    3.94 +}
    3.95 +
    3.96  static const struct wl_pointer_listener pointer_listener = {
    3.97      pointer_handle_enter,
    3.98      pointer_handle_leave,
    3.99 @@ -453,6 +477,164 @@
   3.100      d->input = NULL;
   3.101  }
   3.102  
   3.103 +void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
   3.104 +{
   3.105 +    d->relative_pointer_manager =
   3.106 +        wl_registry_bind(d->registry, id,
   3.107 +                         &zwp_relative_pointer_manager_v1_interface, 1);
   3.108 +}
   3.109 +
   3.110 +void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
   3.111 +{
   3.112 +    if (d->relative_pointer_manager)
   3.113 +        zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
   3.114 +}
   3.115 +
   3.116 +void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
   3.117 +{
   3.118 +    d->pointer_constraints =
   3.119 +        wl_registry_bind(d->registry, id,
   3.120 +                         &zwp_pointer_constraints_v1_interface, 1);
   3.121 +}
   3.122 +
   3.123 +void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
   3.124 +{
   3.125 +    if (d->pointer_constraints)
   3.126 +        zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
   3.127 +}
   3.128 +
   3.129 +static void
   3.130 +relative_pointer_handle_relative_motion(void *data,
   3.131 +                                        struct zwp_relative_pointer_v1 *pointer,
   3.132 +                                        uint32_t time_hi,
   3.133 +                                        uint32_t time_lo,
   3.134 +                                        wl_fixed_t dx_w,
   3.135 +                                        wl_fixed_t dy_w,
   3.136 +                                        wl_fixed_t dx_unaccel_w,
   3.137 +                                        wl_fixed_t dy_unaccel_w)
   3.138 +{
   3.139 +    struct SDL_WaylandInput *input = data;
   3.140 +    SDL_VideoData *d = input->display;
   3.141 +    SDL_WindowData *window = input->pointer_focus;
   3.142 +    double dx_unaccel;
   3.143 +    double dy_unaccel;
   3.144 +    double dx;
   3.145 +    double dy;
   3.146 +
   3.147 +    dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
   3.148 +    dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
   3.149 +
   3.150 +    /* Add left over fraction from last event. */
   3.151 +    dx_unaccel += input->dx_frac;
   3.152 +    dy_unaccel += input->dy_frac;
   3.153 +
   3.154 +    input->dx_frac = modf(dx_unaccel, &dx);
   3.155 +    input->dy_frac = modf(dy_unaccel, &dy);
   3.156 +
   3.157 +    if (input->pointer_focus && d->relative_mouse_mode) {
   3.158 +        SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
   3.159 +    }
   3.160 +}
   3.161 +
   3.162 +static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
   3.163 +    relative_pointer_handle_relative_motion,
   3.164 +};
   3.165 +
   3.166 +static void
   3.167 +locked_pointer_locked(void *data,
   3.168 +                      struct zwp_locked_pointer_v1 *locked_pointer)
   3.169 +{
   3.170 +}
   3.171 +
   3.172 +static void
   3.173 +locked_pointer_unlocked(void *data,
   3.174 +                        struct zwp_locked_pointer_v1 *locked_pointer)
   3.175 +{
   3.176 +}
   3.177 +
   3.178 +static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
   3.179 +    locked_pointer_locked,
   3.180 +    locked_pointer_unlocked,
   3.181 +};
   3.182 +
   3.183 +static void
   3.184 +lock_pointer_to_window(SDL_Window *window,
   3.185 +                       struct SDL_WaylandInput *input)
   3.186 +{
   3.187 +    SDL_WindowData *w = window->driverdata;
   3.188 +    SDL_VideoData *d = input->display;
   3.189 +    struct zwp_locked_pointer_v1 *locked_pointer;
   3.190 +
   3.191 +    if (w->locked_pointer)
   3.192 +        return;
   3.193 +
   3.194 +    locked_pointer =
   3.195 +        zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
   3.196 +                                                w->surface,
   3.197 +                                                input->pointer,
   3.198 +                                                NULL,
   3.199 +                                                ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
   3.200 +    zwp_locked_pointer_v1_add_listener(locked_pointer,
   3.201 +                                       &locked_pointer_listener,
   3.202 +                                       window);
   3.203 +
   3.204 +    w->locked_pointer = locked_pointer;
   3.205 +}
   3.206 +
   3.207 +int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
   3.208 +{
   3.209 +    SDL_VideoDevice *vd = SDL_GetVideoDevice();
   3.210 +    SDL_VideoData *d = input->display;
   3.211 +    SDL_Window *window;
   3.212 +    struct zwp_relative_pointer_v1 *relative_pointer;
   3.213 +
   3.214 +    if (!d->relative_pointer_manager)
   3.215 +        return -1;
   3.216 +
   3.217 +    if (!d->pointer_constraints)
   3.218 +        return -1;
   3.219 +
   3.220 +    if (!input->relative_pointer) {
   3.221 +        relative_pointer =
   3.222 +            zwp_relative_pointer_manager_v1_get_relative_pointer(
   3.223 +                d->relative_pointer_manager,
   3.224 +                input->pointer);
   3.225 +        zwp_relative_pointer_v1_add_listener(relative_pointer,
   3.226 +                                             &relative_pointer_listener,
   3.227 +                                             input);
   3.228 +        input->relative_pointer = relative_pointer;
   3.229 +    }
   3.230 +
   3.231 +    for (window = vd->windows; window; window = window->next)
   3.232 +        lock_pointer_to_window(window, input);
   3.233 +
   3.234 +    d->relative_mouse_mode = 1;
   3.235 +
   3.236 +    return 0;
   3.237 +}
   3.238 +
   3.239 +int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
   3.240 +{
   3.241 +    SDL_VideoDevice *vd = SDL_GetVideoDevice();
   3.242 +    SDL_VideoData *d = input->display;
   3.243 +    SDL_Window *window;
   3.244 +    SDL_WindowData *w;
   3.245 +
   3.246 +    for (window = vd->windows; window; window = window->next) {
   3.247 +        w = window->driverdata;
   3.248 +        if (w->locked_pointer)
   3.249 +            zwp_locked_pointer_v1_destroy(w->locked_pointer);
   3.250 +        w->locked_pointer = NULL;
   3.251 +    }
   3.252 +
   3.253 +    zwp_relative_pointer_v1_destroy(input->relative_pointer);
   3.254 +    input->relative_pointer = NULL;
   3.255 +
   3.256 +    d->relative_mouse_mode = 0;
   3.257 +
   3.258 +    return 0;
   3.259 +}
   3.260 +
   3.261  #endif /* SDL_VIDEO_DRIVER_WAYLAND */
   3.262  
   3.263  /* vi: set ts=4 sw=4 expandtab: */
     4.1 --- a/src/video/wayland/SDL_waylandevents_c.h	Thu Jun 23 18:39:05 2016 +0800
     4.2 +++ b/src/video/wayland/SDL_waylandevents_c.h	Thu Sep 01 01:26:56 2016 -0700
     4.3 @@ -32,6 +32,15 @@
     4.4  extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id);
     4.5  extern void Wayland_display_destroy_input(SDL_VideoData *d);
     4.6  
     4.7 +extern void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id);
     4.8 +extern void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d);
     4.9 +
    4.10 +extern int Wayland_input_lock_pointer(struct SDL_WaylandInput *input);
    4.11 +extern int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input);
    4.12 +
    4.13 +extern void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id);
    4.14 +extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d);
    4.15 +
    4.16  #endif /* _SDL_waylandevents_h */
    4.17  
    4.18  /* vi: set ts=4 sw=4 expandtab: */
     5.1 --- a/src/video/wayland/SDL_waylandmouse.c	Thu Jun 23 18:39:05 2016 +0800
     5.2 +++ b/src/video/wayland/SDL_waylandmouse.c	Thu Sep 01 01:26:56 2016 -0700
     5.3 @@ -365,7 +365,13 @@
     5.4  static int
     5.5  Wayland_SetRelativeMouseMode(SDL_bool enabled)
     5.6  {
     5.7 -    return SDL_Unsupported();
     5.8 +    SDL_VideoDevice *vd = SDL_GetVideoDevice();
     5.9 +    SDL_VideoData *data = (SDL_VideoData *) vd->driverdata;
    5.10 +
    5.11 +    if (enabled)
    5.12 +        return Wayland_input_lock_pointer(data->input);
    5.13 +    else
    5.14 +        return Wayland_input_unlock_pointer(data->input);
    5.15  }
    5.16  
    5.17  void
     6.1 --- a/src/video/wayland/SDL_waylandvideo.c	Thu Jun 23 18:39:05 2016 +0800
     6.2 +++ b/src/video/wayland/SDL_waylandvideo.c	Thu Sep 01 01:26:56 2016 -0700
     6.3 @@ -305,7 +305,10 @@
     6.4      } else if (strcmp(interface, "wl_shm") == 0) {
     6.5          d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
     6.6          d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
     6.7 -
     6.8 +    } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
     6.9 +        Wayland_display_add_relative_pointer_manager(d, id);
    6.10 +    } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
    6.11 +        Wayland_display_add_pointer_constraints(d, id);
    6.12  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    6.13      } else if (strcmp(interface, "qt_touch_extension") == 0) {
    6.14          Wayland_touch_create(d, id);
    6.15 @@ -395,6 +398,8 @@
    6.16      }
    6.17  
    6.18      Wayland_display_destroy_input(data);
    6.19 +    Wayland_display_destroy_pointer_constraints(data);
    6.20 +    Wayland_display_destroy_relative_pointer_manager(data);
    6.21  
    6.22      if (data->xkb_context) {
    6.23          WAYLAND_xkb_context_unref(data->xkb_context);
     7.1 --- a/src/video/wayland/SDL_waylandvideo.h	Thu Jun 23 18:39:05 2016 +0800
     7.2 +++ b/src/video/wayland/SDL_waylandvideo.h	Thu Sep 01 01:26:56 2016 -0700
     7.3 @@ -44,6 +44,8 @@
     7.4      struct wl_cursor_theme *cursor_theme;
     7.5      struct wl_pointer *pointer;
     7.6      struct wl_shell *shell;
     7.7 +    struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
     7.8 +    struct zwp_pointer_constraints_v1 *pointer_constraints;
     7.9  
    7.10      EGLDisplay edpy;
    7.11      EGLContext context;
    7.12 @@ -59,6 +61,8 @@
    7.13  #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
    7.14  
    7.15      char *classname;
    7.16 +
    7.17 +    int relative_mouse_mode;
    7.18  } SDL_VideoData;
    7.19  
    7.20  #endif /* _SDL_waylandvideo_h */
     8.1 --- a/src/video/wayland/SDL_waylandwindow.c	Thu Jun 23 18:39:05 2016 +0800
     8.2 +++ b/src/video/wayland/SDL_waylandwindow.c	Thu Sep 01 01:26:56 2016 -0700
     8.3 @@ -26,6 +26,7 @@
     8.4  #include "../SDL_sysvideo.h"
     8.5  #include "../../events/SDL_windowevents_c.h"
     8.6  #include "../SDL_egl_c.h"
     8.7 +#include "SDL_waylandevents_c.h"
     8.8  #include "SDL_waylandwindow.h"
     8.9  #include "SDL_waylandvideo.h"
    8.10  #include "SDL_waylandtouch.h"
    8.11 @@ -215,6 +216,10 @@
    8.12      wl_surface_set_opaque_region(data->surface, region);
    8.13      wl_region_destroy(region);
    8.14  
    8.15 +    if (c->relative_mouse_mode) {
    8.16 +        Wayland_input_lock_pointer(c->input);
    8.17 +    }
    8.18 +
    8.19      WAYLAND_wl_display_flush(c->display);
    8.20  
    8.21      return 0;
     9.1 --- a/src/video/wayland/SDL_waylandwindow.h	Thu Jun 23 18:39:05 2016 +0800
     9.2 +++ b/src/video/wayland/SDL_waylandwindow.h	Thu Sep 01 01:26:56 2016 -0700
     9.3 @@ -39,6 +39,7 @@
     9.4      struct wl_egl_window *egl_window;
     9.5      struct SDL_WaylandInput *keyboard_device;
     9.6      EGLSurface egl_surface;
     9.7 +    struct zwp_locked_pointer_v1 *locked_pointer;
     9.8  
     9.9  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    9.10      struct qt_extended_surface *extended_surface;