src/video/wayland/SDL_waylandmouse.c
author Philipp Wiesemann
Thu, 14 Apr 2016 21:11:43 +0200
changeset 10154 fae27a079fcb
parent 10130 eba8155e32b1
child 10304 ee83e0b4a36f
permissions -rw-r--r--
Wayland: Removed not needed including and setting of errno.

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