cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_waylandmouse.c (11078B)


      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
     51typedef 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
     63static int
     64wayland_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
     92static void
     93mouse_buffer_release(void *data, struct wl_buffer *buffer)
     94{
     95}
     96
     97static const struct wl_buffer_listener mouse_buffer_listener = {
     98    mouse_buffer_release
     99};
    100
    101static int
    102create_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
    152static SDL_Cursor *
    153Wayland_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
    195static SDL_Cursor *
    196CreateCursorFromWlCursor(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
    220static SDL_Cursor *
    221Wayland_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
    231static SDL_Cursor *
    232Wayland_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
    285static void
    286Wayland_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
    310static int
    311Wayland_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
    344static void
    345Wayland_WarpMouse(SDL_Window *window, int x, int y)
    346{
    347    SDL_Unsupported();
    348}
    349
    350static void
    351Wayland_WarpMouseGlobal(int x, int y)
    352{
    353    SDL_Unsupported();
    354}
    355
    356static int
    357Wayland_SetRelativeMouseMode(SDL_bool enabled)
    358{
    359    SDL_Unsupported();
    360    return -1;
    361}
    362
    363void
    364Wayland_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
    379void
    380Wayland_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 */