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