src/video/wayland/SDL_waylandevents.c
author Ryan C. Gordon
Wed, 07 Feb 2018 13:13:55 -0500
changeset 11848 2f157c1ca383
parent 11813 ea7c4b476853
child 12033 bc702c5a7c3a
permissions -rw-r--r--
wayland: Add support for xdg-shell protocol (unstable v6).

This is meant to be the desktop-enhanced version of wl_shell. Right now we
just match what the existing wl_shell code does, but there are other areas of
functionality available to us now, that we can fill in later.

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