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