src/video/wayland/SDL_waylandevents.c
author Sam Lantinga
Thu, 01 Sep 2016 01:26:56 -0700
changeset 10304 ee83e0b4a36f
parent 10154 fae27a079fcb
child 10583 974f8ebcb819
permissions -rw-r--r--
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.
gabomdq@8062
     1
/*
gabomdq@8062
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
gabomdq@8062
     4
gabomdq@8062
     5
  This software is provided 'as-is', without any express or implied
gabomdq@8062
     6
  warranty.  In no event will the authors be held liable for any damages
gabomdq@8062
     7
  arising from the use of this software.
gabomdq@8062
     8
gabomdq@8062
     9
  Permission is granted to anyone to use this software for any purpose,
gabomdq@8062
    10
  including commercial applications, and to alter it and redistribute it
gabomdq@8062
    11
  freely, subject to the following restrictions:
gabomdq@8062
    12
gabomdq@8062
    13
  1. The origin of this software must not be misrepresented; you must not
gabomdq@8062
    14
     claim that you wrote the original software. If you use this software
gabomdq@8062
    15
     in a product, an acknowledgment in the product documentation would be
gabomdq@8062
    16
     appreciated but is not required.
gabomdq@8062
    17
  2. Altered source versions must be plainly marked as such, and must not be
gabomdq@8062
    18
     misrepresented as being the original software.
gabomdq@8062
    19
  3. This notice may not be removed or altered from any source distribution.
gabomdq@8062
    20
*/
gabomdq@8062
    21
gabomdq@8104
    22
#include "../../SDL_internal.h"
gabomdq@8062
    23
icculus@8116
    24
#if SDL_VIDEO_DRIVER_WAYLAND
icculus@8116
    25
gabomdq@8062
    26
#include "SDL_stdinc.h"
gabomdq@8062
    27
#include "SDL_assert.h"
slouken@10304
    28
#include "SDL_log.h"
gabomdq@8062
    29
gabomdq@8062
    30
#include "../../events/SDL_sysevents.h"
gabomdq@8062
    31
#include "../../events/SDL_events_c.h"
gabomdq@8062
    32
#include "../../events/scancodes_xfree86.h"
gabomdq@8062
    33
gabomdq@8062
    34
#include "SDL_waylandvideo.h"
gabomdq@8062
    35
#include "SDL_waylandevents_c.h"
gabomdq@8062
    36
#include "SDL_waylandwindow.h"
gabomdq@8062
    37
gabomdq@8104
    38
#include "SDL_waylanddyn.h"
gabomdq@8104
    39
slouken@10304
    40
#include "pointer-constraints-unstable-v1-client-protocol.h"
slouken@10304
    41
#include "relative-pointer-unstable-v1-client-protocol.h"
slouken@10304
    42
gabomdq@8062
    43
#include <linux/input.h>
gabomdq@8062
    44
#include <sys/select.h>
gabomdq@8062
    45
#include <sys/mman.h>
gabomdq@8062
    46
#include <poll.h>
gabomdq@8062
    47
#include <unistd.h>
gabomdq@8062
    48
#include <xkbcommon/xkbcommon.h>
gabomdq@8062
    49
gabomdq@8062
    50
struct SDL_WaylandInput {
gabomdq@8062
    51
    SDL_VideoData *display;
gabomdq@8062
    52
    struct wl_seat *seat;
gabomdq@8062
    53
    struct wl_pointer *pointer;
gabomdq@8062
    54
    struct wl_keyboard *keyboard;
slouken@10304
    55
    struct zwp_relative_pointer_v1 *relative_pointer;
gabomdq@8062
    56
    SDL_WindowData *pointer_focus;
gabomdq@8062
    57
    SDL_WindowData *keyboard_focus;
gabomdq@8062
    58
icculus@9554
    59
    /* Last motion location */
icculus@9554
    60
    wl_fixed_t sx_w;
icculus@9554
    61
    wl_fixed_t sy_w;
slouken@10304
    62
slouken@10304
    63
    double dx_frac;
slouken@10304
    64
    double dy_frac;
slouken@10304
    65
gabomdq@8062
    66
    struct {
gabomdq@8062
    67
        struct xkb_keymap *keymap;
gabomdq@8062
    68
        struct xkb_state *state;
gabomdq@8062
    69
    } xkb;
gabomdq@8062
    70
};
gabomdq@8062
    71
gabomdq@8062
    72
void
gabomdq@8062
    73
Wayland_PumpEvents(_THIS)
gabomdq@8062
    74
{
gabomdq@8062
    75
    SDL_VideoData *d = _this->driverdata;
gabomdq@8062
    76
    struct pollfd pfd[1];
gabomdq@8062
    77
gabomdq@8104
    78
    pfd[0].fd = WAYLAND_wl_display_get_fd(d->display);
gabomdq@8062
    79
    pfd[0].events = POLLIN;
gabomdq@8062
    80
    poll(pfd, 1, 0);
gabomdq@8062
    81
gabomdq@8062
    82
    if (pfd[0].revents & POLLIN)
gabomdq@8104
    83
        WAYLAND_wl_display_dispatch(d->display);
gabomdq@8062
    84
    else
gabomdq@8104
    85
        WAYLAND_wl_display_dispatch_pending(d->display);
gabomdq@8062
    86
}
gabomdq@8062
    87
gabomdq@8062
    88
static void
gabomdq@8062
    89
pointer_handle_enter(void *data, struct wl_pointer *pointer,
gabomdq@8062
    90
                     uint32_t serial, struct wl_surface *surface,
gabomdq@8062
    91
                     wl_fixed_t sx_w, wl_fixed_t sy_w)
gabomdq@8062
    92
{
gabomdq@8062
    93
    struct SDL_WaylandInput *input = data;
gabomdq@8062
    94
    SDL_WindowData *window;
gabomdq@8062
    95
gabomdq@8062
    96
    if (!surface) {
gabomdq@8062
    97
        /* enter event for a window we've just destroyed */
gabomdq@8062
    98
        return;
gabomdq@8062
    99
    }
gabomdq@8135
   100
    
gabomdq@8135
   101
    /* This handler will be called twice in Wayland 1.4
gabomdq@8135
   102
     * Once for the window surface which has valid user data
gabomdq@8135
   103
     * and again for the mouse cursor surface which does not have valid user data
gabomdq@8135
   104
     * We ignore the later
gabomdq@8135
   105
     */
gabomdq@8062
   106
gabomdq@8135
   107
    window = (SDL_WindowData *)wl_surface_get_user_data(surface);
gabomdq@8135
   108
    
gabomdq@8135
   109
    if (window) {
gabomdq@8135
   110
        input->pointer_focus = window;
gabomdq@8135
   111
        SDL_SetMouseFocus(window->sdlwindow);
gabomdq@8135
   112
    }
gabomdq@8062
   113
}
gabomdq@8062
   114
gabomdq@8062
   115
static void
gabomdq@8062
   116
pointer_handle_leave(void *data, struct wl_pointer *pointer,
gabomdq@8062
   117
                     uint32_t serial, struct wl_surface *surface)
gabomdq@8062
   118
{
gabomdq@8062
   119
    struct SDL_WaylandInput *input = data;
gabomdq@8062
   120
gabomdq@8135
   121
    if (input->pointer_focus) {
gabomdq@8135
   122
        SDL_SetMouseFocus(NULL);
gabomdq@8135
   123
        input->pointer_focus = NULL;
gabomdq@8135
   124
    }
gabomdq@8062
   125
}
gabomdq@8062
   126
gabomdq@8062
   127
static void
gabomdq@8062
   128
pointer_handle_motion(void *data, struct wl_pointer *pointer,
gabomdq@8062
   129
                      uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
gabomdq@8062
   130
{
gabomdq@8062
   131
    struct SDL_WaylandInput *input = data;
gabomdq@8062
   132
    SDL_WindowData *window = input->pointer_focus;
icculus@9554
   133
    input->sx_w = sx_w;
icculus@9554
   134
    input->sy_w = sy_w;
gabomdq@8135
   135
    if (input->pointer_focus) {
icculus@9556
   136
        const int sx = wl_fixed_to_int(sx_w);
icculus@9556
   137
        const int sy = wl_fixed_to_int(sy_w);
gabomdq@8135
   138
        SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
gabomdq@8135
   139
    }
gabomdq@8062
   140
}
gabomdq@8062
   141
icculus@9554
   142
static SDL_bool
icculus@9554
   143
ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
icculus@9554
   144
{
icculus@9554
   145
    SDL_WindowData *window_data = input->pointer_focus;
icculus@9554
   146
    SDL_Window *window = window_data->sdlwindow;
icculus@9554
   147
icculus@9554
   148
    if (window->hit_test) {
icculus@9554
   149
        const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
icculus@9554
   150
        const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
icculus@9555
   151
        static const uint32_t directions[] = {
icculus@9555
   152
            WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
icculus@9555
   153
            WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
icculus@9555
   154
            WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
icculus@9555
   155
            WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
icculus@9555
   156
        };
icculus@9554
   157
        switch (rc) {
icculus@9555
   158
            case SDL_HITTEST_DRAGGABLE:
icculus@9555
   159
                wl_shell_surface_move(window_data->shell_surface, input->seat, serial);
icculus@9555
   160
                return SDL_TRUE;
icculus@9555
   161
icculus@9555
   162
            case SDL_HITTEST_RESIZE_TOPLEFT:
icculus@9555
   163
            case SDL_HITTEST_RESIZE_TOP:
icculus@9555
   164
            case SDL_HITTEST_RESIZE_TOPRIGHT:
icculus@9555
   165
            case SDL_HITTEST_RESIZE_RIGHT:
icculus@9555
   166
            case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
icculus@9555
   167
            case SDL_HITTEST_RESIZE_BOTTOM:
icculus@9555
   168
            case SDL_HITTEST_RESIZE_BOTTOMLEFT:
icculus@9555
   169
            case SDL_HITTEST_RESIZE_LEFT:
icculus@9555
   170
                wl_shell_surface_resize(window_data->shell_surface, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
icculus@9555
   171
                return SDL_TRUE;
icculus@9555
   172
icculus@9555
   173
            default: return SDL_FALSE;
icculus@9554
   174
        }
icculus@9554
   175
    }
icculus@9554
   176
icculus@9555
   177
    return SDL_FALSE;
icculus@9554
   178
}
icculus@9554
   179
gabomdq@8062
   180
static void
slouken@10304
   181
pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
slouken@10304
   182
                             uint32_t time, uint32_t button, uint32_t state_w)
gabomdq@8062
   183
{
gabomdq@8062
   184
    SDL_WindowData *window = input->pointer_focus;
gabomdq@8062
   185
    enum wl_pointer_button_state state = state_w;
gabomdq@8062
   186
    uint32_t sdl_button;
gabomdq@8135
   187
    
gabomdq@8135
   188
    if  (input->pointer_focus) {
gabomdq@8135
   189
        switch (button) {
gabomdq@8135
   190
            case BTN_LEFT:
gabomdq@8135
   191
                sdl_button = SDL_BUTTON_LEFT;
slouken@10304
   192
                if (ProcessHitTest(input, serial)) {
icculus@9554
   193
                    return;  /* don't pass this event on to app. */
icculus@9554
   194
                }
gabomdq@8135
   195
                break;
gabomdq@8135
   196
            case BTN_MIDDLE:
gabomdq@8135
   197
                sdl_button = SDL_BUTTON_MIDDLE;
gabomdq@8135
   198
                break;
gabomdq@8135
   199
            case BTN_RIGHT:
gabomdq@8135
   200
                sdl_button = SDL_BUTTON_RIGHT;
gabomdq@8135
   201
                break;
gabomdq@8135
   202
            case BTN_SIDE:
gabomdq@8135
   203
                sdl_button = SDL_BUTTON_X1;
gabomdq@8135
   204
                break;
gabomdq@8135
   205
            case BTN_EXTRA:
gabomdq@8135
   206
                sdl_button = SDL_BUTTON_X2;
gabomdq@8135
   207
                break;
gabomdq@8135
   208
            default:
gabomdq@8135
   209
                return;
gabomdq@8135
   210
        }
gabomdq@8062
   211
gabomdq@8135
   212
        SDL_SendMouseButton(window->sdlwindow, 0,
gabomdq@8135
   213
                            state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
gabomdq@8062
   214
    }
gabomdq@8062
   215
}
gabomdq@8062
   216
gabomdq@8062
   217
static void
slouken@10304
   218
pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
slouken@10304
   219
                      uint32_t time, uint32_t button, uint32_t state_w)
gabomdq@8062
   220
{
gabomdq@8062
   221
    struct SDL_WaylandInput *input = data;
slouken@10304
   222
slouken@10304
   223
    pointer_handle_button_common(input, serial, time, button, state_w);
slouken@10304
   224
}
slouken@10304
   225
slouken@10304
   226
static void
slouken@10304
   227
pointer_handle_axis_common(struct SDL_WaylandInput *input,
slouken@10304
   228
                           uint32_t time, uint32_t axis, wl_fixed_t value)
slouken@10304
   229
{
gabomdq@8062
   230
    SDL_WindowData *window = input->pointer_focus;
gabomdq@8062
   231
    enum wl_pointer_axis a = axis;
gabomdq@8062
   232
    int x, y;
gabomdq@8062
   233
gabomdq@8135
   234
    if (input->pointer_focus) {
gabomdq@8135
   235
        switch (a) {
gabomdq@8135
   236
            case WL_POINTER_AXIS_VERTICAL_SCROLL:
gabomdq@8135
   237
                x = 0;
gabomdq@8135
   238
                y = wl_fixed_to_int(value);
gabomdq@8135
   239
                break;
gabomdq@8135
   240
            case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
gabomdq@8135
   241
                x = wl_fixed_to_int(value);
gabomdq@8135
   242
                y = 0;
gabomdq@8135
   243
                break;
gabomdq@8135
   244
            default:
gabomdq@8135
   245
                return;
gabomdq@8135
   246
        }
gabomdq@8135
   247
urkle@9257
   248
        SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
gabomdq@8062
   249
    }
gabomdq@8062
   250
}
gabomdq@8062
   251
slouken@10304
   252
static void
slouken@10304
   253
pointer_handle_axis(void *data, struct wl_pointer *pointer,
slouken@10304
   254
                    uint32_t time, uint32_t axis, wl_fixed_t value)
slouken@10304
   255
{
slouken@10304
   256
    struct SDL_WaylandInput *input = data;
slouken@10304
   257
slouken@10304
   258
    pointer_handle_axis_common(input, time, axis, value);
slouken@10304
   259
}
slouken@10304
   260
gabomdq@8062
   261
static const struct wl_pointer_listener pointer_listener = {
gabomdq@8062
   262
    pointer_handle_enter,
gabomdq@8062
   263
    pointer_handle_leave,
gabomdq@8062
   264
    pointer_handle_motion,
gabomdq@8062
   265
    pointer_handle_button,
gabomdq@8062
   266
    pointer_handle_axis,
gabomdq@8062
   267
};
gabomdq@8062
   268
gabomdq@8062
   269
static void
gabomdq@8062
   270
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
gabomdq@8062
   271
                       uint32_t format, int fd, uint32_t size)
gabomdq@8062
   272
{
gabomdq@8062
   273
    struct SDL_WaylandInput *input = data;
gabomdq@8062
   274
    char *map_str;
gabomdq@8062
   275
gabomdq@8062
   276
    if (!data) {
gabomdq@8062
   277
        close(fd);
gabomdq@8062
   278
        return;
gabomdq@8062
   279
    }
gabomdq@8062
   280
gabomdq@8062
   281
    if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
gabomdq@8062
   282
        close(fd);
gabomdq@8062
   283
        return;
gabomdq@8062
   284
    }
gabomdq@8062
   285
gabomdq@8062
   286
    map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
gabomdq@8062
   287
    if (map_str == MAP_FAILED) {
gabomdq@8062
   288
        close(fd);
gabomdq@8062
   289
        return;
gabomdq@8062
   290
    }
gabomdq@8062
   291
gabomdq@8104
   292
    input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
gabomdq@8062
   293
                                                map_str,
gabomdq@8062
   294
                                                XKB_KEYMAP_FORMAT_TEXT_V1,
gabomdq@8062
   295
                                                0);
gabomdq@8062
   296
    munmap(map_str, size);
gabomdq@8062
   297
    close(fd);
gabomdq@8062
   298
gabomdq@8062
   299
    if (!input->xkb.keymap) {
gabomdq@8062
   300
        fprintf(stderr, "failed to compile keymap\n");
gabomdq@8062
   301
        return;
gabomdq@8062
   302
    }
gabomdq@8062
   303
gabomdq@8104
   304
    input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
gabomdq@8062
   305
    if (!input->xkb.state) {
gabomdq@8062
   306
        fprintf(stderr, "failed to create XKB state\n");
gabomdq@8104
   307
        WAYLAND_xkb_keymap_unref(input->xkb.keymap);
gabomdq@8062
   308
        input->xkb.keymap = NULL;
gabomdq@8062
   309
        return;
gabomdq@8062
   310
    }
gabomdq@8062
   311
}
gabomdq@8062
   312
gabomdq@8062
   313
static void
gabomdq@8062
   314
keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
gabomdq@8062
   315
                      uint32_t serial, struct wl_surface *surface,
gabomdq@8062
   316
                      struct wl_array *keys)
gabomdq@8062
   317
{
gabomdq@8062
   318
    struct SDL_WaylandInput *input = data;
icculus@9656
   319
    SDL_WindowData *window;
icculus@9655
   320
icculus@9655
   321
    if (!surface) {
icculus@9655
   322
        /* enter event for a window we've just destroyed */
icculus@9655
   323
        return;
icculus@9655
   324
    }
icculus@9655
   325
 
icculus@9656
   326
    window = wl_surface_get_user_data(surface);
gabomdq@8062
   327
gabomdq@8135
   328
    if (window) {
philipp@10099
   329
        input->keyboard_focus = window;
philipp@10099
   330
        window->keyboard_device = input;
gabomdq@8135
   331
        SDL_SetKeyboardFocus(window->sdlwindow);
gabomdq@8135
   332
    }
gabomdq@8062
   333
}
gabomdq@8062
   334
gabomdq@8062
   335
static void
gabomdq@8062
   336
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
gabomdq@8062
   337
                      uint32_t serial, struct wl_surface *surface)
gabomdq@8062
   338
{
gabomdq@8062
   339
    SDL_SetKeyboardFocus(NULL);
gabomdq@8062
   340
}
gabomdq@8062
   341
gabomdq@8062
   342
static void
gabomdq@8062
   343
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
gabomdq@8062
   344
                    uint32_t serial, uint32_t time, uint32_t key,
gabomdq@8062
   345
                    uint32_t state_w)
gabomdq@8062
   346
{
gabomdq@8062
   347
    struct SDL_WaylandInput *input = data;
gabomdq@8062
   348
    SDL_WindowData *window = input->keyboard_focus;
gabomdq@8062
   349
    enum wl_keyboard_key_state state = state_w;
gabomdq@8062
   350
    const xkb_keysym_t *syms;
gabomdq@8062
   351
    uint32_t scancode;
gabomdq@8062
   352
    char text[8];
gabomdq@8062
   353
    int size;
gabomdq@8062
   354
gabomdq@8062
   355
    if (key < SDL_arraysize(xfree86_scancode_table2)) {
gabomdq@8062
   356
        scancode = xfree86_scancode_table2[key];
gabomdq@8062
   357
gabomdq@8062
   358
        // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
gabomdq@8062
   359
        if (scancode != SDL_SCANCODE_UNKNOWN)
gabomdq@8062
   360
            SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
gabomdq@8062
   361
                                SDL_PRESSED : SDL_RELEASED, scancode);
gabomdq@8062
   362
    }
gabomdq@8062
   363
gabomdq@8062
   364
    if (!window || window->keyboard_device != input || !input->xkb.state)
gabomdq@8062
   365
        return;
gabomdq@8062
   366
gabomdq@8062
   367
    // TODO can this happen?
gabomdq@8104
   368
    if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
gabomdq@8062
   369
        return;
gabomdq@8062
   370
gabomdq@8062
   371
    if (state) {
gabomdq@8104
   372
        size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
gabomdq@8062
   373
gabomdq@8062
   374
        if (size > 0) {
gabomdq@8062
   375
            text[size] = 0;
gabomdq@8062
   376
            SDL_SendKeyboardText(text);
gabomdq@8062
   377
        }
gabomdq@8062
   378
    }
gabomdq@8062
   379
}
gabomdq@8062
   380
gabomdq@8062
   381
static void
gabomdq@8062
   382
keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
gabomdq@8062
   383
                          uint32_t serial, uint32_t mods_depressed,
gabomdq@8062
   384
                          uint32_t mods_latched, uint32_t mods_locked,
gabomdq@8062
   385
                          uint32_t group)
gabomdq@8062
   386
{
gabomdq@8062
   387
    struct SDL_WaylandInput *input = data;
gabomdq@8062
   388
gabomdq@8104
   389
    WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
gabomdq@8062
   390
                          mods_locked, 0, 0, group);
gabomdq@8062
   391
}
gabomdq@8062
   392
gabomdq@8062
   393
static const struct wl_keyboard_listener keyboard_listener = {
gabomdq@8062
   394
    keyboard_handle_keymap,
gabomdq@8062
   395
    keyboard_handle_enter,
gabomdq@8062
   396
    keyboard_handle_leave,
gabomdq@8062
   397
    keyboard_handle_key,
gabomdq@8062
   398
    keyboard_handle_modifiers,
gabomdq@8062
   399
};
gabomdq@8062
   400
gabomdq@8062
   401
static void
gabomdq@8062
   402
seat_handle_capabilities(void *data, struct wl_seat *seat,
gabomdq@8062
   403
                         enum wl_seat_capability caps)
gabomdq@8062
   404
{
gabomdq@8062
   405
    struct SDL_WaylandInput *input = data;
gabomdq@8062
   406
gabomdq@8062
   407
    if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
gabomdq@8062
   408
        input->pointer = wl_seat_get_pointer(seat);
gabomdq@8062
   409
        input->display->pointer = input->pointer;
gabomdq@8062
   410
        wl_pointer_set_user_data(input->pointer, input);
gabomdq@8062
   411
        wl_pointer_add_listener(input->pointer, &pointer_listener,
gabomdq@8062
   412
                                input);
gabomdq@8062
   413
    } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
gabomdq@8062
   414
        wl_pointer_destroy(input->pointer);
gabomdq@8062
   415
        input->pointer = NULL;
gabomdq@8062
   416
    }
gabomdq@8062
   417
gabomdq@8062
   418
    if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
gabomdq@8062
   419
        input->keyboard = wl_seat_get_keyboard(seat);
gabomdq@8062
   420
        wl_keyboard_set_user_data(input->keyboard, input);
gabomdq@8062
   421
        wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
gabomdq@8062
   422
                                 input);
gabomdq@8062
   423
    } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
gabomdq@8062
   424
        wl_keyboard_destroy(input->keyboard);
gabomdq@8062
   425
        input->keyboard = NULL;
gabomdq@8062
   426
    }
gabomdq@8062
   427
}
gabomdq@8062
   428
gabomdq@8062
   429
static const struct wl_seat_listener seat_listener = {
gabomdq@8062
   430
    seat_handle_capabilities,
gabomdq@8062
   431
};
gabomdq@8062
   432
gabomdq@8062
   433
void
gabomdq@8062
   434
Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
gabomdq@8062
   435
{
gabomdq@8062
   436
    struct SDL_WaylandInput *input;
gabomdq@8062
   437
gabomdq@8135
   438
    input = SDL_calloc(1, sizeof *input);
gabomdq@8062
   439
    if (input == NULL)
gabomdq@8062
   440
        return;
gabomdq@8062
   441
gabomdq@8062
   442
    input->display = d;
gabomdq@8062
   443
    input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
icculus@9554
   444
    input->sx_w = wl_fixed_from_int(0);
icculus@9554
   445
    input->sy_w = wl_fixed_from_int(0);
gabomdq@8062
   446
    d->input = input;
gabomdq@8062
   447
gabomdq@8062
   448
    wl_seat_add_listener(input->seat, &seat_listener, input);
gabomdq@8062
   449
    wl_seat_set_user_data(input->seat, input);
gabomdq@8062
   450
gabomdq@8104
   451
    WAYLAND_wl_display_flush(d->display);
gabomdq@8062
   452
}
gabomdq@8062
   453
gabomdq@8062
   454
void Wayland_display_destroy_input(SDL_VideoData *d)
gabomdq@8062
   455
{
gabomdq@8062
   456
    struct SDL_WaylandInput *input = d->input;
gabomdq@8062
   457
gabomdq@8062
   458
    if (!input)
gabomdq@8062
   459
        return;
gabomdq@8062
   460
gabomdq@8062
   461
    if (input->keyboard)
gabomdq@8062
   462
        wl_keyboard_destroy(input->keyboard);
gabomdq@8062
   463
gabomdq@8062
   464
    if (input->pointer)
gabomdq@8062
   465
        wl_pointer_destroy(input->pointer);
gabomdq@8062
   466
gabomdq@8062
   467
    if (input->seat)
gabomdq@8062
   468
        wl_seat_destroy(input->seat);
gabomdq@8062
   469
gabomdq@8062
   470
    if (input->xkb.state)
gabomdq@8104
   471
        WAYLAND_xkb_state_unref(input->xkb.state);
gabomdq@8062
   472
gabomdq@8062
   473
    if (input->xkb.keymap)
gabomdq@8104
   474
        WAYLAND_xkb_keymap_unref(input->xkb.keymap);
gabomdq@8062
   475
gabomdq@8135
   476
    SDL_free(input);
gabomdq@8062
   477
    d->input = NULL;
gabomdq@8062
   478
}
gabomdq@8062
   479
slouken@10304
   480
void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
slouken@10304
   481
{
slouken@10304
   482
    d->relative_pointer_manager =
slouken@10304
   483
        wl_registry_bind(d->registry, id,
slouken@10304
   484
                         &zwp_relative_pointer_manager_v1_interface, 1);
slouken@10304
   485
}
slouken@10304
   486
slouken@10304
   487
void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
slouken@10304
   488
{
slouken@10304
   489
    if (d->relative_pointer_manager)
slouken@10304
   490
        zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
slouken@10304
   491
}
slouken@10304
   492
slouken@10304
   493
void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
slouken@10304
   494
{
slouken@10304
   495
    d->pointer_constraints =
slouken@10304
   496
        wl_registry_bind(d->registry, id,
slouken@10304
   497
                         &zwp_pointer_constraints_v1_interface, 1);
slouken@10304
   498
}
slouken@10304
   499
slouken@10304
   500
void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
slouken@10304
   501
{
slouken@10304
   502
    if (d->pointer_constraints)
slouken@10304
   503
        zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
slouken@10304
   504
}
slouken@10304
   505
slouken@10304
   506
static void
slouken@10304
   507
relative_pointer_handle_relative_motion(void *data,
slouken@10304
   508
                                        struct zwp_relative_pointer_v1 *pointer,
slouken@10304
   509
                                        uint32_t time_hi,
slouken@10304
   510
                                        uint32_t time_lo,
slouken@10304
   511
                                        wl_fixed_t dx_w,
slouken@10304
   512
                                        wl_fixed_t dy_w,
slouken@10304
   513
                                        wl_fixed_t dx_unaccel_w,
slouken@10304
   514
                                        wl_fixed_t dy_unaccel_w)
slouken@10304
   515
{
slouken@10304
   516
    struct SDL_WaylandInput *input = data;
slouken@10304
   517
    SDL_VideoData *d = input->display;
slouken@10304
   518
    SDL_WindowData *window = input->pointer_focus;
slouken@10304
   519
    double dx_unaccel;
slouken@10304
   520
    double dy_unaccel;
slouken@10304
   521
    double dx;
slouken@10304
   522
    double dy;
slouken@10304
   523
slouken@10304
   524
    dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
slouken@10304
   525
    dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
slouken@10304
   526
slouken@10304
   527
    /* Add left over fraction from last event. */
slouken@10304
   528
    dx_unaccel += input->dx_frac;
slouken@10304
   529
    dy_unaccel += input->dy_frac;
slouken@10304
   530
slouken@10304
   531
    input->dx_frac = modf(dx_unaccel, &dx);
slouken@10304
   532
    input->dy_frac = modf(dy_unaccel, &dy);
slouken@10304
   533
slouken@10304
   534
    if (input->pointer_focus && d->relative_mouse_mode) {
slouken@10304
   535
        SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
slouken@10304
   536
    }
slouken@10304
   537
}
slouken@10304
   538
slouken@10304
   539
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
slouken@10304
   540
    relative_pointer_handle_relative_motion,
slouken@10304
   541
};
slouken@10304
   542
slouken@10304
   543
static void
slouken@10304
   544
locked_pointer_locked(void *data,
slouken@10304
   545
                      struct zwp_locked_pointer_v1 *locked_pointer)
slouken@10304
   546
{
slouken@10304
   547
}
slouken@10304
   548
slouken@10304
   549
static void
slouken@10304
   550
locked_pointer_unlocked(void *data,
slouken@10304
   551
                        struct zwp_locked_pointer_v1 *locked_pointer)
slouken@10304
   552
{
slouken@10304
   553
}
slouken@10304
   554
slouken@10304
   555
static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
slouken@10304
   556
    locked_pointer_locked,
slouken@10304
   557
    locked_pointer_unlocked,
slouken@10304
   558
};
slouken@10304
   559
slouken@10304
   560
static void
slouken@10304
   561
lock_pointer_to_window(SDL_Window *window,
slouken@10304
   562
                       struct SDL_WaylandInput *input)
slouken@10304
   563
{
slouken@10304
   564
    SDL_WindowData *w = window->driverdata;
slouken@10304
   565
    SDL_VideoData *d = input->display;
slouken@10304
   566
    struct zwp_locked_pointer_v1 *locked_pointer;
slouken@10304
   567
slouken@10304
   568
    if (w->locked_pointer)
slouken@10304
   569
        return;
slouken@10304
   570
slouken@10304
   571
    locked_pointer =
slouken@10304
   572
        zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
slouken@10304
   573
                                                w->surface,
slouken@10304
   574
                                                input->pointer,
slouken@10304
   575
                                                NULL,
slouken@10304
   576
                                                ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
slouken@10304
   577
    zwp_locked_pointer_v1_add_listener(locked_pointer,
slouken@10304
   578
                                       &locked_pointer_listener,
slouken@10304
   579
                                       window);
slouken@10304
   580
slouken@10304
   581
    w->locked_pointer = locked_pointer;
slouken@10304
   582
}
slouken@10304
   583
slouken@10304
   584
int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
slouken@10304
   585
{
slouken@10304
   586
    SDL_VideoDevice *vd = SDL_GetVideoDevice();
slouken@10304
   587
    SDL_VideoData *d = input->display;
slouken@10304
   588
    SDL_Window *window;
slouken@10304
   589
    struct zwp_relative_pointer_v1 *relative_pointer;
slouken@10304
   590
slouken@10304
   591
    if (!d->relative_pointer_manager)
slouken@10304
   592
        return -1;
slouken@10304
   593
slouken@10304
   594
    if (!d->pointer_constraints)
slouken@10304
   595
        return -1;
slouken@10304
   596
slouken@10304
   597
    if (!input->relative_pointer) {
slouken@10304
   598
        relative_pointer =
slouken@10304
   599
            zwp_relative_pointer_manager_v1_get_relative_pointer(
slouken@10304
   600
                d->relative_pointer_manager,
slouken@10304
   601
                input->pointer);
slouken@10304
   602
        zwp_relative_pointer_v1_add_listener(relative_pointer,
slouken@10304
   603
                                             &relative_pointer_listener,
slouken@10304
   604
                                             input);
slouken@10304
   605
        input->relative_pointer = relative_pointer;
slouken@10304
   606
    }
slouken@10304
   607
slouken@10304
   608
    for (window = vd->windows; window; window = window->next)
slouken@10304
   609
        lock_pointer_to_window(window, input);
slouken@10304
   610
slouken@10304
   611
    d->relative_mouse_mode = 1;
slouken@10304
   612
slouken@10304
   613
    return 0;
slouken@10304
   614
}
slouken@10304
   615
slouken@10304
   616
int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
slouken@10304
   617
{
slouken@10304
   618
    SDL_VideoDevice *vd = SDL_GetVideoDevice();
slouken@10304
   619
    SDL_VideoData *d = input->display;
slouken@10304
   620
    SDL_Window *window;
slouken@10304
   621
    SDL_WindowData *w;
slouken@10304
   622
slouken@10304
   623
    for (window = vd->windows; window; window = window->next) {
slouken@10304
   624
        w = window->driverdata;
slouken@10304
   625
        if (w->locked_pointer)
slouken@10304
   626
            zwp_locked_pointer_v1_destroy(w->locked_pointer);
slouken@10304
   627
        w->locked_pointer = NULL;
slouken@10304
   628
    }
slouken@10304
   629
slouken@10304
   630
    zwp_relative_pointer_v1_destroy(input->relative_pointer);
slouken@10304
   631
    input->relative_pointer = NULL;
slouken@10304
   632
slouken@10304
   633
    d->relative_mouse_mode = 0;
slouken@10304
   634
slouken@10304
   635
    return 0;
slouken@10304
   636
}
slouken@10304
   637
icculus@8116
   638
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
icculus@8116
   639
gabomdq@8062
   640
/* vi: set ts=4 sw=4 expandtab: */