cscg22-gearboy

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

SDL_waylandvideo.c (12284B)


      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#include "SDL_video.h"
     27#include "SDL_mouse.h"
     28#include "SDL_stdinc.h"
     29#include "../../events/SDL_events_c.h"
     30
     31#include "SDL_waylandvideo.h"
     32#include "SDL_waylandevents_c.h"
     33#include "SDL_waylandwindow.h"
     34#include "SDL_waylandopengles.h"
     35#include "SDL_waylandmouse.h"
     36#include "SDL_waylandtouch.h"
     37
     38#include <fcntl.h>
     39#include <xkbcommon/xkbcommon.h>
     40
     41#include "SDL_waylanddyn.h"
     42#include <wayland-util.h>
     43
     44#define WAYLANDVID_DRIVER_NAME "wayland"
     45
     46struct wayland_mode {
     47    SDL_DisplayMode mode;
     48    struct wl_list link;
     49};
     50
     51/* Initialization/Query functions */
     52static int
     53Wayland_VideoInit(_THIS);
     54
     55static void
     56Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
     57static int
     58Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
     59
     60static void
     61Wayland_VideoQuit(_THIS);
     62
     63/* Wayland driver bootstrap functions */
     64static int
     65Wayland_Available(void)
     66{
     67    struct wl_display *display = NULL;
     68    if (SDL_WAYLAND_LoadSymbols()) {
     69        display = WAYLAND_wl_display_connect(NULL);
     70        if (display != NULL) {
     71            WAYLAND_wl_display_disconnect(display);
     72        }
     73        SDL_WAYLAND_UnloadSymbols();
     74    }
     75
     76    return (display != NULL);
     77}
     78
     79static void
     80Wayland_DeleteDevice(SDL_VideoDevice *device)
     81{
     82    SDL_free(device);
     83    SDL_WAYLAND_UnloadSymbols();
     84}
     85
     86static SDL_VideoDevice *
     87Wayland_CreateDevice(int devindex)
     88{
     89    SDL_VideoDevice *device;
     90    
     91    if (!SDL_WAYLAND_LoadSymbols()) {
     92        return NULL;
     93    }
     94
     95    /* Initialize all variables that we clean on shutdown */
     96    device = SDL_calloc(1, sizeof(SDL_VideoDevice));
     97    if (!device) {
     98        SDL_WAYLAND_UnloadSymbols();
     99        SDL_OutOfMemory();
    100        return NULL;
    101    }
    102
    103    /* Set the function pointers */
    104    device->VideoInit = Wayland_VideoInit;
    105    device->VideoQuit = Wayland_VideoQuit;
    106    device->SetDisplayMode = Wayland_SetDisplayMode;
    107    device->GetDisplayModes = Wayland_GetDisplayModes;
    108    device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
    109
    110    device->PumpEvents = Wayland_PumpEvents;
    111
    112    device->GL_SwapWindow = Wayland_GLES_SwapWindow;
    113    device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
    114    device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
    115    device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
    116    device->GL_CreateContext = Wayland_GLES_CreateContext;
    117    device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
    118    device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
    119    device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
    120    device->GL_DeleteContext = Wayland_GLES_DeleteContext;
    121
    122    device->CreateWindow = Wayland_CreateWindow;
    123    device->ShowWindow = Wayland_ShowWindow;
    124    device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
    125    device->SetWindowSize = Wayland_SetWindowSize;
    126    device->DestroyWindow = Wayland_DestroyWindow;
    127
    128    device->free = Wayland_DeleteDevice;
    129
    130    return device;
    131}
    132
    133VideoBootStrap Wayland_bootstrap = {
    134    WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
    135    Wayland_Available, Wayland_CreateDevice
    136};
    137
    138static void
    139wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
    140{
    141    struct wayland_mode *mode;
    142
    143    /* Check for duplicate mode */
    144    wl_list_for_each(mode, &d->modes_list, link)
    145        if (mode->mode.w == m.w && mode->mode.h == m.h &&
    146	    mode->mode.refresh_rate == m.refresh_rate)
    147	    return;
    148
    149    /* Add new mode to the list */
    150    mode = (struct wayland_mode *) SDL_calloc(1, sizeof *mode);
    151
    152    if (!mode)
    153	return;
    154
    155    mode->mode = m;
    156    WAYLAND_wl_list_insert(&d->modes_list, &mode->link);
    157}
    158
    159static void
    160display_handle_geometry(void *data,
    161                        struct wl_output *output,
    162                        int x, int y,
    163                        int physical_width,
    164                        int physical_height,
    165                        int subpixel,
    166                        const char *make,
    167                        const char *model,
    168                        int transform)
    169
    170{
    171    SDL_VideoData *d = data;
    172
    173    d->screen_allocation.x = x;
    174    d->screen_allocation.y = y;
    175}
    176
    177static void
    178display_handle_mode(void *data,
    179                    struct wl_output *wl_output,
    180                    uint32_t flags,
    181                    int width,
    182                    int height,
    183                    int refresh)
    184{
    185    SDL_VideoData *d = data;
    186    SDL_DisplayMode mode;
    187
    188    SDL_zero(mode);
    189    mode.w = width;
    190    mode.h = height;
    191    mode.refresh_rate = refresh / 1000;
    192
    193    wayland_add_mode(d, mode);
    194
    195    if (flags & WL_OUTPUT_MODE_CURRENT) {
    196        d->screen_allocation.width = width;
    197        d->screen_allocation.height = height;
    198    }
    199}
    200
    201static const struct wl_output_listener output_listener = {
    202    display_handle_geometry,
    203    display_handle_mode
    204};
    205
    206static void
    207shm_handle_format(void *data,
    208                  struct wl_shm *shm,
    209                  uint32_t format)
    210{
    211    SDL_VideoData *d = data;
    212
    213    d->shm_formats |= (1 << format);
    214}
    215
    216static const struct wl_shm_listener shm_listener = {
    217    shm_handle_format
    218};
    219
    220#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    221static void
    222windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
    223        int32_t show_is_fullscreen)
    224{
    225}
    226
    227static void
    228windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
    229{
    230    SDL_SendQuit();
    231}
    232
    233static const struct qt_windowmanager_listener windowmanager_listener = {
    234    windowmanager_hints,
    235    windowmanager_quit,
    236};
    237#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
    238
    239static void
    240display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
    241					const char *interface, uint32_t version)
    242{
    243    SDL_VideoData *d = data;
    244    
    245    if (strcmp(interface, "wl_compositor") == 0) {
    246        d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
    247    } else if (strcmp(interface, "wl_output") == 0) {
    248        d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
    249        wl_output_add_listener(d->output, &output_listener, d);
    250    } else if (strcmp(interface, "wl_seat") == 0) {
    251        Wayland_display_add_input(d, id);
    252    } else if (strcmp(interface, "wl_shell") == 0) {
    253        d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
    254    } else if (strcmp(interface, "wl_shm") == 0) {
    255        d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
    256        d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
    257        d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
    258        wl_shm_add_listener(d->shm, &shm_listener, d);
    259    
    260#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    261    } else if (strcmp(interface, "qt_touch_extension") == 0) {
    262        Wayland_touch_create(d, id);
    263    } else if (strcmp(interface, "qt_surface_extension") == 0) {
    264        d->surface_extension = wl_registry_bind(registry, id,
    265                &qt_surface_extension_interface, 1);
    266    } else if (strcmp(interface, "qt_windowmanager") == 0) {
    267        d->windowmanager = wl_registry_bind(registry, id,
    268                &qt_windowmanager_interface, 1);
    269        qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
    270#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
    271    }
    272}
    273
    274static const struct wl_registry_listener registry_listener = {
    275	display_handle_global
    276};
    277
    278int
    279Wayland_VideoInit(_THIS)
    280{
    281    SDL_VideoData *data;
    282    SDL_VideoDisplay display;
    283    SDL_DisplayMode mode;
    284    int i;
    285    
    286    data = malloc(sizeof *data);
    287    if (data == NULL)
    288        return 0;
    289    memset(data, 0, sizeof *data);
    290
    291    _this->driverdata = data;
    292
    293    WAYLAND_wl_list_init(&data->modes_list);
    294    
    295    data->display = WAYLAND_wl_display_connect(NULL);
    296    if (data->display == NULL) {
    297        SDL_SetError("Failed to connect to a Wayland display");
    298        return 0;
    299    }
    300
    301    data->registry = wl_display_get_registry(data->display);
    302   
    303    if ( data->registry == NULL) {
    304        SDL_SetError("Failed to get the Wayland registry");
    305        return 0;
    306    }
    307    
    308    wl_registry_add_listener(data->registry, &registry_listener, data);
    309
    310    for (i=0; i < 100; i++) {
    311        if (data->screen_allocation.width != 0 || WAYLAND_wl_display_get_error(data->display) != 0) {
    312            break;
    313        }
    314        WAYLAND_wl_display_dispatch(data->display);
    315    }
    316    
    317    if (data->screen_allocation.width == 0) {
    318        SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display));
    319        return 0;
    320    }
    321
    322    data->xkb_context = WAYLAND_xkb_context_new(0);
    323    if (!data->xkb_context) {
    324        SDL_SetError("Failed to create XKB context");
    325        return 0;
    326    }
    327
    328    /* Use a fake 32-bpp desktop mode */
    329    mode.format = SDL_PIXELFORMAT_RGB888;
    330    mode.w = data->screen_allocation.width;
    331    mode.h = data->screen_allocation.height;
    332    mode.refresh_rate = 0;
    333    mode.driverdata = NULL;
    334    wayland_add_mode(data, mode);
    335    SDL_zero(display);
    336    display.desktop_mode = mode;
    337    display.current_mode = mode;
    338    display.driverdata = NULL;
    339    SDL_AddVideoDisplay(&display);
    340
    341    Wayland_InitMouse ();
    342
    343    WAYLAND_wl_display_flush(data->display);
    344
    345    return 0;
    346}
    347
    348static void
    349Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
    350{
    351    SDL_VideoData *data = _this->driverdata;
    352    SDL_DisplayMode mode;
    353    struct wayland_mode *m;
    354
    355    Wayland_PumpEvents(_this);
    356
    357    wl_list_for_each(m, &data->modes_list, link) {
    358        m->mode.format = SDL_PIXELFORMAT_RGB888;
    359        SDL_AddDisplayMode(sdl_display, &m->mode);
    360        m->mode.format = SDL_PIXELFORMAT_RGBA8888;
    361        SDL_AddDisplayMode(sdl_display, &m->mode);
    362    }
    363
    364    mode.w = data->screen_allocation.width;
    365    mode.h = data->screen_allocation.height;
    366    mode.refresh_rate = 0;
    367    mode.driverdata = NULL;
    368
    369    mode.format = SDL_PIXELFORMAT_RGB888;
    370    SDL_AddDisplayMode(sdl_display, &mode);
    371    mode.format = SDL_PIXELFORMAT_RGBA8888;
    372    SDL_AddDisplayMode(sdl_display, &mode);
    373}
    374
    375static int
    376Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
    377{
    378    return 0;
    379}
    380
    381void
    382Wayland_VideoQuit(_THIS)
    383{
    384    SDL_VideoData *data = _this->driverdata;
    385    struct wayland_mode *t, *m;
    386
    387    Wayland_FiniMouse ();
    388
    389    if (data->output)
    390        wl_output_destroy(data->output);
    391
    392    Wayland_display_destroy_input(data);
    393
    394    if (data->xkb_context) {
    395        WAYLAND_xkb_context_unref(data->xkb_context);
    396        data->xkb_context = NULL;
    397    }
    398#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    399    if (data->windowmanager)
    400        qt_windowmanager_destroy(data->windowmanager);
    401
    402    if (data->surface_extension)
    403        qt_surface_extension_destroy(data->surface_extension);
    404
    405    Wayland_touch_destroy(data);
    406#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
    407
    408    if (data->shm)
    409        wl_shm_destroy(data->shm);
    410
    411    if (data->cursor_theme)
    412        WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
    413
    414    if (data->shell)
    415        wl_shell_destroy(data->shell);
    416
    417    if (data->compositor)
    418        wl_compositor_destroy(data->compositor);
    419
    420    if (data->display) {
    421        WAYLAND_wl_display_flush(data->display);
    422        WAYLAND_wl_display_disconnect(data->display);
    423    }
    424    
    425    wl_list_for_each_safe(m, t, &data->modes_list, link) {
    426        WAYLAND_wl_list_remove(&m->link);
    427        free(m);
    428    }
    429
    430
    431    free(data);
    432    _this->driverdata = NULL;
    433}
    434
    435#endif /* SDL_VIDEO_DRIVER_WAYLAND */
    436
    437/* vi: set ts=4 sw=4 expandtab: */