src/video/wayland/SDL_waylandevents.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 30 Oct 2016 21:01:33 +0100
changeset 10563 e3d84016cb79
parent 10304 ee83e0b4a36f
child 10583 974f8ebcb819
permissions -rw-r--r--
Fixed outdated info in README.
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: */