sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_waylandmouse.c (10938B)


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