src/video/wayland/SDL_waylandmouse.c
author Arne Janbu <arnej@arnej.de>
Sat, 10 Jan 2015 13:47:37 +0100
changeset 9362 dfd8202eb9a7
parent 9136 64fcdfcd5bca
child 9469 3f8d36ffd19d
permissions -rw-r--r--
Fix build on Linux when wayland is enabled

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