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