src/video/wayland/SDL_waylandmouse.c
author Gabriel Jacobo
Sat, 14 Dec 2013 20:18:43 -0300
changeset 8062 4fc5f66d63cc
child 8104 2e4f1bd21196
permissions -rw-r--r--
Wayland support

Based on the original port to Wayland by: Joel Teichroeb, Benjamin Franzke, Scott Moreau, et al.

Additional changes in this commit, done by me:

* Wayland uses the common EGL framework
* EGL can now create a desktop OpenGL context
* testgl2 loads GL functions dynamically, no need to link to libGL anymore
* Assorted fixes to the Wayland backend

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