src/video/wayland/SDL_waylandmouse.c
author Ryan C. Gordon
Fri, 17 Jul 2015 21:03:58 -0400
changeset 9807 57b448735f48
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
SDL_WarpMouseGlobal() should return non-void.

There are platforms it isn't implemented on (and currently can't be
implemented on!), and there's currently no way for an app to know this.

This shouldn't break ABI on apps that moved to a revision between 2.0.3 and
2.0.4.
gabomdq@8062
     1
/*
gabomdq@8062
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 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
icculus@8116
    22
#include "../../SDL_internal.h"
icculus@8116
    23
icculus@8116
    24
#if SDL_VIDEO_DRIVER_WAYLAND
icculus@8116
    25
gabomdq@8062
    26
#ifndef _GNU_SOURCE
gabomdq@8062
    27
#define _GNU_SOURCE
gabomdq@8062
    28
#endif
gabomdq@8062
    29
gabomdq@8062
    30
#include <errno.h>
gabomdq@8062
    31
#include <sys/types.h>
gabomdq@8062
    32
#include <sys/mman.h>
gabomdq@8062
    33
#include <fcntl.h>
gabomdq@8062
    34
#include <unistd.h>
gabomdq@8062
    35
#include <stdlib.h>
gabomdq@8062
    36
#include <limits.h>
gabomdq@8062
    37
gabomdq@8062
    38
#include "../SDL_sysvideo.h"
gabomdq@8062
    39
gabomdq@8062
    40
#include "SDL_mouse.h"
gabomdq@8062
    41
#include "../../events/SDL_mouse_c.h"
gabomdq@8062
    42
#include "SDL_waylandvideo.h"
gabomdq@8062
    43
#include "SDL_waylandevents_c.h"
gabomdq@8062
    44
gabomdq@8104
    45
#include "SDL_waylanddyn.h"
gabomdq@8104
    46
#include "wayland-cursor.h"
gabomdq@8104
    47
gabomdq@8062
    48
#include "SDL_assert.h"
gabomdq@8062
    49
gabomdq@8062
    50
gabomdq@8062
    51
typedef struct {
gabomdq@8062
    52
    struct wl_buffer   *buffer;
gabomdq@8062
    53
    struct wl_surface  *surface;
gabomdq@8062
    54
gabomdq@8062
    55
    int                hot_x, hot_y;
slouken@8711
    56
    int                w, h;
gabomdq@8062
    57
gabomdq@8062
    58
    /* Either a preloaded cursor, or one we created ourselves */
gabomdq@8062
    59
    struct wl_cursor   *cursor;
gabomdq@8062
    60
    void               *shm_data;
gabomdq@8062
    61
} Wayland_CursorData;
gabomdq@8062
    62
gabomdq@8062
    63
static int
gabomdq@8062
    64
wayland_create_tmp_file(off_t size)
gabomdq@8062
    65
{
gabomdq@8062
    66
    static const char template[] = "/sdl-shared-XXXXXX";
gabomdq@8062
    67
    char *xdg_path;
gabomdq@8062
    68
    char tmp_path[PATH_MAX];
gabomdq@8062
    69
    int fd;
gabomdq@8062
    70
gabomdq@8062
    71
    xdg_path = SDL_getenv("XDG_RUNTIME_DIR");
gabomdq@8062
    72
    if (!xdg_path) {
gabomdq@8062
    73
        errno = ENOENT;
gabomdq@8062
    74
        return -1;
gabomdq@8062
    75
    }
gabomdq@8062
    76
gabomdq@8062
    77
    SDL_strlcpy(tmp_path, xdg_path, PATH_MAX);
gabomdq@8062
    78
    SDL_strlcat(tmp_path, template, PATH_MAX);
gabomdq@8062
    79
gabomdq@8062
    80
    fd = mkostemp(tmp_path, O_CLOEXEC);
gabomdq@8062
    81
    if (fd < 0)
gabomdq@8062
    82
        return -1;
gabomdq@8062
    83
gabomdq@8062
    84
    if (ftruncate(fd, size) < 0) {
gabomdq@8062
    85
        close(fd);
gabomdq@8062
    86
        return -1;
gabomdq@8062
    87
    }
gabomdq@8062
    88
gabomdq@8062
    89
    return fd;
gabomdq@8062
    90
}
gabomdq@8062
    91
gabomdq@8062
    92
static void
gabomdq@8062
    93
mouse_buffer_release(void *data, struct wl_buffer *buffer)
gabomdq@8062
    94
{
gabomdq@8062
    95
}
gabomdq@8062
    96
gabomdq@8062
    97
static const struct wl_buffer_listener mouse_buffer_listener = {
gabomdq@8062
    98
    mouse_buffer_release
gabomdq@8062
    99
};
gabomdq@8062
   100
gabomdq@8062
   101
static int
gabomdq@8062
   102
create_buffer_from_shm(Wayland_CursorData *d,
gabomdq@8062
   103
                       int width,
gabomdq@8062
   104
                       int height,
gabomdq@8062
   105
                       uint32_t format)
gabomdq@8062
   106
{
gabomdq@8062
   107
    SDL_VideoDevice *vd = SDL_GetVideoDevice();
gabomdq@8062
   108
    SDL_VideoData *data = (SDL_VideoData *) vd->driverdata;
icculus@8721
   109
    struct wl_shm_pool *shm_pool;
gabomdq@8062
   110
gabomdq@8062
   111
    int stride = width * 4;
gabomdq@8062
   112
    int size = stride * height;
gabomdq@8062
   113
gabomdq@8062
   114
    int shm_fd;
gabomdq@8062
   115
gabomdq@8062
   116
    shm_fd = wayland_create_tmp_file(size);
gabomdq@8062
   117
    if (shm_fd < 0)
gabomdq@8062
   118
    {
gabomdq@8062
   119
        fprintf(stderr, "creating mouse cursor buffer failed!\n");
gabomdq@8062
   120
        return -1;
gabomdq@8062
   121
    }
gabomdq@8062
   122
gabomdq@8062
   123
    d->shm_data = mmap(NULL,
gabomdq@8062
   124
                       size,
gabomdq@8062
   125
                       PROT_READ | PROT_WRITE,
gabomdq@8062
   126
                       MAP_SHARED,
gabomdq@8062
   127
                       shm_fd,
gabomdq@8062
   128
                       0);
ryomnktml@9136
   129
    if (d->shm_data == MAP_FAILED) {
gabomdq@8062
   130
        d->shm_data = NULL;
gabomdq@8062
   131
        fprintf (stderr, "mmap () failed\n");
gabomdq@8062
   132
        close (shm_fd);
gabomdq@8062
   133
    }
gabomdq@8062
   134
icculus@8721
   135
    shm_pool = wl_shm_create_pool(data->shm, shm_fd, size);
gabomdq@8062
   136
    d->buffer = wl_shm_pool_create_buffer(shm_pool,
gabomdq@8062
   137
                                          0,
gabomdq@8062
   138
                                          width,
gabomdq@8062
   139
                                          height,
gabomdq@8062
   140
                                          stride,
gabomdq@8062
   141
                                          format);
gabomdq@8062
   142
    wl_buffer_add_listener(d->buffer,
gabomdq@8062
   143
                           &mouse_buffer_listener,
gabomdq@8062
   144
                           d);
gabomdq@8062
   145
gabomdq@8062
   146
    wl_shm_pool_destroy (shm_pool);
gabomdq@8062
   147
    close (shm_fd);
gabomdq@8062
   148
gabomdq@8062
   149
    return 0;
gabomdq@8062
   150
}
gabomdq@8062
   151
gabomdq@8062
   152
static SDL_Cursor *
gabomdq@8062
   153
Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
gabomdq@8062
   154
{
gabomdq@8062
   155
    SDL_Cursor *cursor;
gabomdq@8062
   156
gabomdq@8062
   157
    cursor = calloc(1, sizeof (*cursor));
gabomdq@8062
   158
    if (cursor) {
gabomdq@8062
   159
        SDL_VideoDevice *vd = SDL_GetVideoDevice ();
gabomdq@8062
   160
        SDL_VideoData *wd = (SDL_VideoData *) vd->driverdata;
gabomdq@8062
   161
        Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData));
gabomdq@8062
   162
        cursor->driverdata = (void *) data;
gabomdq@8062
   163
gabomdq@8062
   164
        /* Assume ARGB8888 */
gabomdq@8062
   165
        SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
gabomdq@8062
   166
        SDL_assert(surface->pitch == surface->w * 4);
gabomdq@8062
   167
gabomdq@8062
   168
        /* Allocate shared memory buffer for this cursor */
gabomdq@8062
   169
        if (create_buffer_from_shm (data,
gabomdq@8062
   170
                                    surface->w,
gabomdq@8062
   171
                                    surface->h,
gabomdq@8062
   172
                                    WL_SHM_FORMAT_XRGB8888) < 0)
gabomdq@8062
   173
        {
gabomdq@8062
   174
            free (cursor->driverdata);
gabomdq@8062
   175
            free (cursor);
gabomdq@8062
   176
            return NULL;
gabomdq@8062
   177
        }
gabomdq@8062
   178
gabomdq@8062
   179
        SDL_memcpy(data->shm_data,
gabomdq@8062
   180
                   surface->pixels,
gabomdq@8062
   181
                   surface->h * surface->pitch);
gabomdq@8062
   182
gabomdq@8062
   183
        data->surface = wl_compositor_create_surface(wd->compositor);
gabomdq@8135
   184
        wl_surface_set_user_data(data->surface, NULL);
gabomdq@8062
   185
gabomdq@8062
   186
        data->hot_x = hot_x;
gabomdq@8062
   187
        data->hot_y = hot_y;
slouken@8711
   188
        data->w = surface->w;
slouken@8711
   189
        data->h = surface->h;
gabomdq@8062
   190
    }
gabomdq@8062
   191
gabomdq@8062
   192
    return cursor;
gabomdq@8062
   193
}
gabomdq@8062
   194
gabomdq@8062
   195
static SDL_Cursor *
gabomdq@8062
   196
CreateCursorFromWlCursor(SDL_VideoData *d, struct wl_cursor *wlcursor)
gabomdq@8062
   197
{
gabomdq@8062
   198
    SDL_Cursor *cursor;
gabomdq@8062
   199
gabomdq@8062
   200
    cursor = calloc(1, sizeof (*cursor));
gabomdq@8062
   201
    if (cursor) {
gabomdq@8062
   202
        Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData));
gabomdq@8062
   203
        cursor->driverdata = (void *) data;
gabomdq@8062
   204
slouken@8711
   205
        data->buffer = WAYLAND_wl_cursor_image_get_buffer(wlcursor->images[0]);
gabomdq@8062
   206
        data->surface = wl_compositor_create_surface(d->compositor);
gabomdq@8135
   207
        wl_surface_set_user_data(data->surface, NULL);
gabomdq@8062
   208
        data->hot_x = wlcursor->images[0]->hotspot_x;
gabomdq@8062
   209
        data->hot_y = wlcursor->images[0]->hotspot_y;
slouken@8711
   210
        data->w = wlcursor->images[0]->width;
slouken@8711
   211
        data->h = wlcursor->images[0]->height;
gabomdq@8062
   212
        data->cursor= wlcursor;
gabomdq@8062
   213
    } else {
gabomdq@8062
   214
        SDL_OutOfMemory ();
gabomdq@8062
   215
    }
gabomdq@8062
   216
gabomdq@8062
   217
    return cursor;
gabomdq@8062
   218
}
gabomdq@8062
   219
gabomdq@8062
   220
static SDL_Cursor *
gabomdq@8062
   221
Wayland_CreateDefaultCursor()
gabomdq@8062
   222
{
gabomdq@8062
   223
    SDL_VideoDevice *device = SDL_GetVideoDevice();
gabomdq@8062
   224
    SDL_VideoData *data = device->driverdata;
gabomdq@8062
   225
gabomdq@8062
   226
    return CreateCursorFromWlCursor (data,
gabomdq@8104
   227
                                     WAYLAND_wl_cursor_theme_get_cursor(data->cursor_theme,
gabomdq@8062
   228
                                                                "left_ptr"));
gabomdq@8062
   229
}
gabomdq@8062
   230
gabomdq@8062
   231
static SDL_Cursor *
gabomdq@8062
   232
Wayland_CreateSystemCursor(SDL_SystemCursor id)
gabomdq@8062
   233
{
gabomdq@8062
   234
    SDL_VideoDevice *vd = SDL_GetVideoDevice();
gabomdq@8062
   235
    SDL_VideoData *d = vd->driverdata;
gabomdq@8062
   236
gabomdq@8062
   237
    struct wl_cursor *cursor = NULL;
gabomdq@8062
   238
gabomdq@8062
   239
    switch(id)
gabomdq@8062
   240
    {
gabomdq@8062
   241
    default:
gabomdq@8062
   242
        SDL_assert(0);
gabomdq@8062
   243
        return NULL;
gabomdq@8062
   244
    case SDL_SYSTEM_CURSOR_ARROW:
gabomdq@8104
   245
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
gabomdq@8062
   246
        break;
gabomdq@8062
   247
    case SDL_SYSTEM_CURSOR_IBEAM:
gabomdq@8104
   248
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
gabomdq@8062
   249
        break;
gabomdq@8062
   250
    case SDL_SYSTEM_CURSOR_WAIT:
slouken@8710
   251
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "watch");
gabomdq@8062
   252
        break;
gabomdq@8062
   253
    case SDL_SYSTEM_CURSOR_CROSSHAIR:
gabomdq@8104
   254
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   255
        break;
gabomdq@8062
   256
    case SDL_SYSTEM_CURSOR_WAITARROW:
slouken@8710
   257
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "watch");
gabomdq@8062
   258
        break;
gabomdq@8062
   259
    case SDL_SYSTEM_CURSOR_SIZENWSE:
gabomdq@8104
   260
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   261
        break;
gabomdq@8062
   262
    case SDL_SYSTEM_CURSOR_SIZENESW:
gabomdq@8104
   263
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   264
        break;
gabomdq@8062
   265
    case SDL_SYSTEM_CURSOR_SIZEWE:
gabomdq@8104
   266
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   267
        break;
gabomdq@8062
   268
    case SDL_SYSTEM_CURSOR_SIZENS:
gabomdq@8104
   269
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   270
        break;
gabomdq@8062
   271
    case SDL_SYSTEM_CURSOR_SIZEALL:
gabomdq@8104
   272
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   273
        break;
gabomdq@8062
   274
    case SDL_SYSTEM_CURSOR_NO:
gabomdq@8104
   275
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
gabomdq@8062
   276
        break;
gabomdq@8062
   277
    case SDL_SYSTEM_CURSOR_HAND:
gabomdq@8104
   278
        cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
gabomdq@8062
   279
        break;
gabomdq@8062
   280
    }
gabomdq@8062
   281
icculus@8721
   282
    return CreateCursorFromWlCursor(d, cursor);
gabomdq@8062
   283
}
gabomdq@8062
   284
gabomdq@8062
   285
static void
gabomdq@8062
   286
Wayland_FreeCursor(SDL_Cursor *cursor)
gabomdq@8062
   287
{
icculus@8721
   288
    Wayland_CursorData *d;
icculus@8721
   289
gabomdq@8062
   290
    if (!cursor)
gabomdq@8062
   291
        return;
gabomdq@8062
   292
icculus@8721
   293
    d = cursor->driverdata;
gabomdq@8062
   294
gabomdq@8062
   295
    /* Probably not a cursor we own */
gabomdq@8062
   296
    if (!d)
gabomdq@8062
   297
        return;
gabomdq@8062
   298
slouken@8711
   299
    if (d->buffer && !d->cursor)
gabomdq@8062
   300
        wl_buffer_destroy(d->buffer);
gabomdq@8062
   301
gabomdq@8062
   302
    if (d->surface)
gabomdq@8062
   303
        wl_surface_destroy(d->surface);
gabomdq@8062
   304
gabomdq@8062
   305
    /* Not sure what's meant to happen to shm_data */
gabomdq@8062
   306
    free (cursor->driverdata);
gabomdq@8062
   307
    SDL_free(cursor);
gabomdq@8062
   308
}
gabomdq@8062
   309
gabomdq@8062
   310
static int
gabomdq@8062
   311
Wayland_ShowCursor(SDL_Cursor *cursor)
gabomdq@8062
   312
{
gabomdq@8062
   313
    SDL_VideoDevice *vd = SDL_GetVideoDevice();
gabomdq@8062
   314
    SDL_VideoData *d = vd->driverdata;
gabomdq@8062
   315
gabomdq@8062
   316
    struct wl_pointer *pointer = d->pointer;
gabomdq@8062
   317
gabomdq@8062
   318
    if (!pointer)
gabomdq@8062
   319
        return -1;
gabomdq@8062
   320
gabomdq@8062
   321
    if (cursor)
gabomdq@8062
   322
    {
gabomdq@8062
   323
        Wayland_CursorData *data = cursor->driverdata;
gabomdq@8062
   324
slouken@8711
   325
        wl_surface_attach(data->surface, data->buffer, 0, 0);
slouken@8711
   326
        wl_surface_damage(data->surface, 0, 0, data->w, data->h);
slouken@8711
   327
        wl_surface_commit(data->surface);
gabomdq@8062
   328
        wl_pointer_set_cursor (pointer, 0,
gabomdq@8062
   329
                               data->surface,
gabomdq@8062
   330
                               data->hot_x,
gabomdq@8062
   331
                               data->hot_y);
gabomdq@8062
   332
    }
gabomdq@8062
   333
    else
gabomdq@8062
   334
    {
gabomdq@8062
   335
        wl_pointer_set_cursor (pointer, 0,
gabomdq@8062
   336
                               NULL,
gabomdq@8062
   337
                               0,
gabomdq@8062
   338
                               0);
gabomdq@8062
   339
    }
gabomdq@8062
   340
    
gabomdq@8062
   341
    return 0;
gabomdq@8062
   342
}
gabomdq@8062
   343
gabomdq@8062
   344
static void
gabomdq@8062
   345
Wayland_WarpMouse(SDL_Window *window, int x, int y)
gabomdq@8062
   346
{
gabomdq@8062
   347
    SDL_Unsupported();
slouken@8815
   348
}
slouken@8815
   349
icculus@9807
   350
static int
slouken@8815
   351
Wayland_WarpMouseGlobal(int x, int y)
slouken@8815
   352
{
icculus@9807
   353
    return SDL_Unsupported();
gabomdq@8062
   354
}
gabomdq@8062
   355
gabomdq@8062
   356
static int
gabomdq@8062
   357
Wayland_SetRelativeMouseMode(SDL_bool enabled)
gabomdq@8062
   358
{
icculus@9469
   359
    return SDL_Unsupported();
gabomdq@8062
   360
}
gabomdq@8062
   361
gabomdq@8062
   362
void
gabomdq@8062
   363
Wayland_InitMouse(void)
gabomdq@8062
   364
{
gabomdq@8062
   365
    SDL_Mouse *mouse = SDL_GetMouse();
gabomdq@8062
   366
gabomdq@8062
   367
    mouse->CreateCursor = Wayland_CreateCursor;
gabomdq@8062
   368
    mouse->CreateSystemCursor = Wayland_CreateSystemCursor;
gabomdq@8062
   369
    mouse->ShowCursor = Wayland_ShowCursor;
gabomdq@8062
   370
    mouse->FreeCursor = Wayland_FreeCursor;
gabomdq@8062
   371
    mouse->WarpMouse = Wayland_WarpMouse;
slouken@8815
   372
    mouse->WarpMouseGlobal = Wayland_WarpMouseGlobal;
gabomdq@8062
   373
    mouse->SetRelativeMouseMode = Wayland_SetRelativeMouseMode;
gabomdq@8062
   374
gabomdq@8062
   375
    SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
gabomdq@8062
   376
}
gabomdq@8062
   377
gabomdq@8062
   378
void
gabomdq@8062
   379
Wayland_FiniMouse(void)
gabomdq@8062
   380
{
gabomdq@8062
   381
    /* This effectively assumes that nobody else
gabomdq@8062
   382
     * touches SDL_Mouse which is effectively
gabomdq@8062
   383
     * a singleton */
gabomdq@8062
   384
gabomdq@8062
   385
    SDL_Mouse *mouse = SDL_GetMouse();
gabomdq@8062
   386
gabomdq@8062
   387
    /* Free the current cursor if not the same pointer as
gabomdq@8062
   388
     * the default cursor */
gabomdq@8062
   389
    if (mouse->def_cursor != mouse->cur_cursor)
gabomdq@8062
   390
        Wayland_FreeCursor (mouse->cur_cursor);
gabomdq@8062
   391
gabomdq@8062
   392
    Wayland_FreeCursor (mouse->def_cursor);
gabomdq@8062
   393
    mouse->def_cursor = NULL;
gabomdq@8062
   394
    mouse->cur_cursor = NULL;
gabomdq@8062
   395
gabomdq@8062
   396
    mouse->CreateCursor =  NULL;
gabomdq@8062
   397
    mouse->CreateSystemCursor = NULL;
gabomdq@8062
   398
    mouse->ShowCursor = NULL;
gabomdq@8062
   399
    mouse->FreeCursor = NULL;
gabomdq@8062
   400
    mouse->WarpMouse = NULL;
gabomdq@8062
   401
    mouse->SetRelativeMouseMode = NULL;
gabomdq@8062
   402
}
icculus@8116
   403
#endif  /* SDL_VIDEO_DRIVER_WAYLAND */