cscg22-gearboy

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

SDL_video.c (91179B)


      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#include "../SDL_internal.h"
     22
     23/* The high-level video driver subsystem */
     24
     25#include "SDL.h"
     26#include "SDL_video.h"
     27#include "SDL_sysvideo.h"
     28#include "SDL_blit.h"
     29#include "SDL_pixels_c.h"
     30#include "SDL_rect_c.h"
     31#include "../events/SDL_events_c.h"
     32#include "../timer/SDL_timer_c.h"
     33
     34#include "SDL_syswm.h"
     35
     36#if SDL_VIDEO_OPENGL
     37#include "SDL_opengl.h"
     38#endif /* SDL_VIDEO_OPENGL */
     39
     40#if SDL_VIDEO_OPENGL_ES
     41#include "SDL_opengles.h"
     42#endif /* SDL_VIDEO_OPENGL_ES */
     43
     44/* GL and GLES2 headers conflict on Linux 32 bits */
     45#if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL
     46#include "SDL_opengles2.h"
     47#endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */
     48
     49/* On Windows, windows.h defines CreateWindow */
     50#ifdef CreateWindow
     51#undef CreateWindow
     52#endif
     53
     54/* Available video drivers */
     55static VideoBootStrap *bootstrap[] = {
     56#if SDL_VIDEO_DRIVER_COCOA
     57    &COCOA_bootstrap,
     58#endif
     59#if SDL_VIDEO_DRIVER_X11
     60    &X11_bootstrap,
     61#endif
     62#if SDL_VIDEO_DRIVER_MIR
     63    &MIR_bootstrap,
     64#endif
     65#if SDL_VIDEO_DRIVER_WAYLAND
     66    &Wayland_bootstrap,
     67#endif
     68#if SDL_VIDEO_DRIVER_VIVANTE
     69    &VIVANTE_bootstrap,
     70#endif
     71#if SDL_VIDEO_DRIVER_DIRECTFB
     72    &DirectFB_bootstrap,
     73#endif
     74#if SDL_VIDEO_DRIVER_WINDOWS
     75    &WINDOWS_bootstrap,
     76#endif
     77#if SDL_VIDEO_DRIVER_WINRT
     78    &WINRT_bootstrap,
     79#endif
     80#if SDL_VIDEO_DRIVER_HAIKU
     81    &HAIKU_bootstrap,
     82#endif
     83#if SDL_VIDEO_DRIVER_PANDORA
     84    &PND_bootstrap,
     85#endif
     86#if SDL_VIDEO_DRIVER_UIKIT
     87    &UIKIT_bootstrap,
     88#endif
     89#if SDL_VIDEO_DRIVER_ANDROID
     90    &Android_bootstrap,
     91#endif
     92#if SDL_VIDEO_DRIVER_PSP
     93    &PSP_bootstrap,
     94#endif
     95#if SDL_VIDEO_DRIVER_RPI
     96    &RPI_bootstrap,
     97#endif 
     98#if SDL_VIDEO_DRIVER_NACL
     99    &NACL_bootstrap,
    100#endif
    101#if SDL_VIDEO_DRIVER_DUMMY
    102    &DUMMY_bootstrap,
    103#endif
    104    NULL
    105};
    106
    107static SDL_VideoDevice *_this = NULL;
    108
    109#define CHECK_WINDOW_MAGIC(window, retval) \
    110    if (!_this) { \
    111        SDL_UninitializedVideo(); \
    112        return retval; \
    113    } \
    114    if (!window || window->magic != &_this->window_magic) { \
    115        SDL_SetError("Invalid window"); \
    116        return retval; \
    117    }
    118
    119#define CHECK_DISPLAY_INDEX(displayIndex, retval) \
    120    if (!_this) { \
    121        SDL_UninitializedVideo(); \
    122        return retval; \
    123    } \
    124    SDL_assert(_this->displays != NULL); \
    125    if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
    126        SDL_SetError("displayIndex must be in the range 0 - %d", \
    127                     _this->num_displays - 1); \
    128        return retval; \
    129    }
    130
    131#define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
    132
    133#ifdef __MACOSX__
    134/* Support for Mac OS X fullscreen spaces */
    135extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window);
    136extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state);
    137#endif
    138
    139
    140/* Support for framebuffer emulation using an accelerated renderer */
    141
    142#define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
    143
    144typedef struct {
    145    SDL_Renderer *renderer;
    146    SDL_Texture *texture;
    147    void *pixels;
    148    int pitch;
    149    int bytes_per_pixel;
    150} SDL_WindowTextureData;
    151
    152static SDL_bool
    153ShouldUseTextureFramebuffer()
    154{
    155    const char *hint;
    156
    157    /* If there's no native framebuffer support then there's no option */
    158    if (!_this->CreateWindowFramebuffer) {
    159        return SDL_TRUE;
    160    }
    161
    162    /* If the user has specified a software renderer we can't use a
    163       texture framebuffer, or renderer creation will go recursive.
    164     */
    165    hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
    166    if (hint && SDL_strcasecmp(hint, "software") == 0) {
    167        return SDL_FALSE;
    168    }
    169
    170    /* See if the user or application wants a specific behavior */
    171    hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
    172    if (hint) {
    173        if (*hint == '0') {
    174            return SDL_FALSE;
    175        } else {
    176            return SDL_TRUE;
    177        }
    178    }
    179
    180    /* Each platform has different performance characteristics */
    181#if defined(__WIN32__)
    182    /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
    183     */
    184    return SDL_FALSE;
    185
    186#elif defined(__MACOSX__)
    187    /* Mac OS X uses OpenGL as the native fast path */
    188    return SDL_TRUE;
    189
    190#elif defined(__LINUX__)
    191    /* Properly configured OpenGL drivers are faster than MIT-SHM */
    192#if SDL_VIDEO_OPENGL
    193    /* Ugh, find a way to cache this value! */
    194    {
    195        SDL_Window *window;
    196        SDL_GLContext context;
    197        SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
    198
    199        window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
    200        if (window) {
    201            context = SDL_GL_CreateContext(window);
    202            if (context) {
    203                const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
    204                const char *vendor = NULL;
    205
    206                glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
    207                if (glGetStringFunc) {
    208                    vendor = (const char *) glGetStringFunc(GL_VENDOR);
    209                }
    210                /* Add more vendors here at will... */
    211                if (vendor &&
    212                    (SDL_strstr(vendor, "ATI Technologies") ||
    213                     SDL_strstr(vendor, "NVIDIA"))) {
    214                    hasAcceleratedOpenGL = SDL_TRUE;
    215                }
    216                SDL_GL_DeleteContext(context);
    217            }
    218            SDL_DestroyWindow(window);
    219        }
    220        return hasAcceleratedOpenGL;
    221    }
    222#elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
    223    /* Let's be optimistic about this! */
    224    return SDL_TRUE;
    225#else
    226    return SDL_FALSE;
    227#endif
    228
    229#else
    230    /* Play it safe, assume that if there is a framebuffer driver that it's
    231       optimized for the current platform.
    232    */
    233    return SDL_FALSE;
    234#endif
    235}
    236
    237static int
    238SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
    239{
    240    SDL_WindowTextureData *data;
    241
    242    data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
    243    if (!data) {
    244        SDL_Renderer *renderer = NULL;
    245        int i;
    246        const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
    247
    248        /* Check to see if there's a specific driver requested */
    249        if (hint && *hint != '0' && *hint != '1' &&
    250            SDL_strcasecmp(hint, "software") != 0) {
    251            for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
    252                SDL_RendererInfo info;
    253                SDL_GetRenderDriverInfo(i, &info);
    254                if (SDL_strcasecmp(info.name, hint) == 0) {
    255                    renderer = SDL_CreateRenderer(window, i, 0);
    256                    break;
    257                }
    258            }
    259        }
    260        
    261        if (!renderer) {
    262            for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
    263                SDL_RendererInfo info;
    264                SDL_GetRenderDriverInfo(i, &info);
    265                if (SDL_strcmp(info.name, "software") != 0) {
    266                    renderer = SDL_CreateRenderer(window, i, 0);
    267                    if (renderer) {
    268                        break;
    269                    }
    270                }
    271            }
    272        }
    273        if (!renderer) {
    274            return SDL_SetError("No hardware accelerated renderers available");
    275        }
    276
    277        /* Create the data after we successfully create the renderer (bug #1116) */
    278        data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
    279        if (!data) {
    280            SDL_DestroyRenderer(renderer);
    281            return SDL_OutOfMemory();
    282        }
    283        SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
    284
    285        data->renderer = renderer;
    286    }
    287
    288    /* Free any old texture and pixel data */
    289    if (data->texture) {
    290        SDL_DestroyTexture(data->texture);
    291        data->texture = NULL;
    292    }
    293    SDL_free(data->pixels);
    294    data->pixels = NULL;
    295
    296    {
    297        SDL_RendererInfo info;
    298        Uint32 i;
    299
    300        if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
    301            return -1;
    302        }
    303
    304        /* Find the first format without an alpha channel */
    305        *format = info.texture_formats[0];
    306
    307        for (i = 0; i < info.num_texture_formats; ++i) {
    308            if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
    309                    !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
    310                *format = info.texture_formats[i];
    311                break;
    312            }
    313        }
    314    }
    315
    316    data->texture = SDL_CreateTexture(data->renderer, *format,
    317                                      SDL_TEXTUREACCESS_STREAMING,
    318                                      window->w, window->h);
    319    if (!data->texture) {
    320        return -1;
    321    }
    322
    323    /* Create framebuffer data */
    324    data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
    325    data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
    326    data->pixels = SDL_malloc(window->h * data->pitch);
    327    if (!data->pixels) {
    328        return SDL_OutOfMemory();
    329    }
    330
    331    *pixels = data->pixels;
    332    *pitch = data->pitch;
    333
    334    /* Make sure we're not double-scaling the viewport */
    335    SDL_RenderSetViewport(data->renderer, NULL);
    336
    337    return 0;
    338}
    339
    340static int
    341SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects)
    342{
    343    SDL_WindowTextureData *data;
    344    SDL_Rect rect;
    345    void *src;
    346
    347    data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
    348    if (!data || !data->texture) {
    349        return SDL_SetError("No window texture data");
    350    }
    351
    352    /* Update a single rect that contains subrects for best DMA performance */
    353    if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
    354        src = (void *)((Uint8 *)data->pixels +
    355                        rect.y * data->pitch +
    356                        rect.x * data->bytes_per_pixel);
    357        if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
    358            return -1;
    359        }
    360
    361        if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
    362            return -1;
    363        }
    364
    365        SDL_RenderPresent(data->renderer);
    366    }
    367    return 0;
    368}
    369
    370static void
    371SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window)
    372{
    373    SDL_WindowTextureData *data;
    374
    375    data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
    376    if (!data) {
    377        return;
    378    }
    379    if (data->texture) {
    380        SDL_DestroyTexture(data->texture);
    381    }
    382    if (data->renderer) {
    383        SDL_DestroyRenderer(data->renderer);
    384    }
    385    SDL_free(data->pixels);
    386    SDL_free(data);
    387}
    388
    389
    390static int
    391cmpmodes(const void *A, const void *B)
    392{
    393    const SDL_DisplayMode *a = (const SDL_DisplayMode *) A;
    394    const SDL_DisplayMode *b = (const SDL_DisplayMode *) B;
    395    if (a == b) {
    396        return 0;
    397    } else if (a->w != b->w) {
    398        return b->w - a->w;
    399    } else if (a->h != b->h) {
    400        return b->h - a->h;
    401    } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) {
    402        return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format);
    403    } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) {
    404        return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format);
    405    } else if (a->refresh_rate != b->refresh_rate) {
    406        return b->refresh_rate - a->refresh_rate;
    407    }
    408    return 0;
    409}
    410
    411static int
    412SDL_UninitializedVideo()
    413{
    414    return SDL_SetError("Video subsystem has not been initialized");
    415}
    416
    417int
    418SDL_GetNumVideoDrivers(void)
    419{
    420    return SDL_arraysize(bootstrap) - 1;
    421}
    422
    423const char *
    424SDL_GetVideoDriver(int index)
    425{
    426    if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
    427        return bootstrap[index]->name;
    428    }
    429    return NULL;
    430}
    431
    432/*
    433 * Initialize the video and event subsystems -- determine native pixel format
    434 */
    435int
    436SDL_VideoInit(const char *driver_name)
    437{
    438    SDL_VideoDevice *video;
    439    const char *hint;
    440    int index;
    441    int i;
    442    SDL_bool allow_screensaver;
    443
    444    /* Check to make sure we don't overwrite '_this' */
    445    if (_this != NULL) {
    446        SDL_VideoQuit();
    447    }
    448
    449#if !SDL_TIMERS_DISABLED
    450    SDL_TicksInit();
    451#endif
    452
    453    /* Start the event loop */
    454    if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||
    455        SDL_KeyboardInit() < 0 ||
    456        SDL_MouseInit() < 0 ||
    457        SDL_TouchInit() < 0) {
    458        return -1;
    459    }
    460
    461    /* Select the proper video driver */
    462    index = 0;
    463    video = NULL;
    464    if (driver_name == NULL) {
    465        driver_name = SDL_getenv("SDL_VIDEODRIVER");
    466    }
    467    if (driver_name != NULL) {
    468        for (i = 0; bootstrap[i]; ++i) {
    469            if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {
    470                if (bootstrap[i]->available()) {
    471                    video = bootstrap[i]->create(index);
    472                    break;
    473                }
    474            }
    475        }
    476    } else {
    477        for (i = 0; bootstrap[i]; ++i) {
    478            if (bootstrap[i]->available()) {
    479                video = bootstrap[i]->create(index);
    480                if (video != NULL) {
    481                    break;
    482                }
    483            }
    484        }
    485    }
    486    if (video == NULL) {
    487        if (driver_name) {
    488            return SDL_SetError("%s not available", driver_name);
    489        }
    490        return SDL_SetError("No available video device");
    491    }
    492    _this = video;
    493    _this->name = bootstrap[i]->name;
    494    _this->next_object_id = 1;
    495
    496
    497    /* Set some very sane GL defaults */
    498    _this->gl_config.driver_loaded = 0;
    499    _this->gl_config.dll_handle = NULL;
    500    SDL_GL_ResetAttributes();
    501
    502    _this->current_glwin_tls = SDL_TLSCreate();
    503    _this->current_glctx_tls = SDL_TLSCreate();
    504
    505    /* Initialize the video subsystem */
    506    if (_this->VideoInit(_this) < 0) {
    507        SDL_VideoQuit();
    508        return -1;
    509    }
    510
    511    /* Make sure some displays were added */
    512    if (_this->num_displays == 0) {
    513        SDL_VideoQuit();
    514        return SDL_SetError("The video driver did not add any displays");
    515    }
    516
    517    /* Add the renderer framebuffer emulation if desired */
    518    if (ShouldUseTextureFramebuffer()) {
    519        _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
    520        _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
    521        _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
    522    }
    523
    524    /* Disable the screen saver by default. This is a change from <= 2.0.1,
    525       but most things using SDL are games or media players; you wouldn't
    526       want a screensaver to trigger if you're playing exclusively with a
    527       joystick, or passively watching a movie. Things that use SDL but
    528       function more like a normal desktop app should explicitly reenable the
    529       screensaver. */
    530    hint = SDL_GetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER);
    531    if (hint) {
    532        allow_screensaver = SDL_atoi(hint) ? SDL_TRUE : SDL_FALSE;
    533    } else {
    534        allow_screensaver = SDL_FALSE;
    535    }
    536    if (!allow_screensaver) {
    537        SDL_DisableScreenSaver();
    538    }
    539
    540    /* If we don't use a screen keyboard, turn on text input by default,
    541       otherwise programs that expect to get text events without enabling
    542       UNICODE input won't get any events.
    543
    544       Actually, come to think of it, you needed to call SDL_EnableUNICODE(1)
    545       in SDL 1.2 before you got text input events.  Hmm...
    546     */
    547    if (!SDL_HasScreenKeyboardSupport()) {
    548        SDL_StartTextInput();
    549    }
    550
    551    /* We're ready to go! */
    552    return 0;
    553}
    554
    555const char *
    556SDL_GetCurrentVideoDriver()
    557{
    558    if (!_this) {
    559        SDL_UninitializedVideo();
    560        return NULL;
    561    }
    562    return _this->name;
    563}
    564
    565SDL_VideoDevice *
    566SDL_GetVideoDevice(void)
    567{
    568    return _this;
    569}
    570
    571int
    572SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
    573{
    574    SDL_VideoDisplay display;
    575
    576    SDL_zero(display);
    577    if (desktop_mode) {
    578        display.desktop_mode = *desktop_mode;
    579    }
    580    display.current_mode = display.desktop_mode;
    581
    582    return SDL_AddVideoDisplay(&display);
    583}
    584
    585int
    586SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
    587{
    588    SDL_VideoDisplay *displays;
    589    int index = -1;
    590
    591    displays =
    592        SDL_realloc(_this->displays,
    593                    (_this->num_displays + 1) * sizeof(*displays));
    594    if (displays) {
    595        index = _this->num_displays++;
    596        displays[index] = *display;
    597        displays[index].device = _this;
    598        _this->displays = displays;
    599
    600        if (display->name) {
    601            displays[index].name = SDL_strdup(display->name);
    602        } else {
    603            char name[32];
    604
    605            SDL_itoa(index, name, 10);
    606            displays[index].name = SDL_strdup(name);
    607        }
    608    } else {
    609        SDL_OutOfMemory();
    610    }
    611    return index;
    612}
    613
    614int
    615SDL_GetNumVideoDisplays(void)
    616{
    617    if (!_this) {
    618        SDL_UninitializedVideo();
    619        return 0;
    620    }
    621    return _this->num_displays;
    622}
    623
    624static int
    625SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
    626{
    627    int displayIndex;
    628
    629    for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
    630        if (display == &_this->displays[displayIndex]) {
    631            return displayIndex;
    632        }
    633    }
    634
    635    /* Couldn't find the display, just use index 0 */
    636    return 0;
    637}
    638
    639void *
    640SDL_GetDisplayDriverData(int displayIndex)
    641{
    642    CHECK_DISPLAY_INDEX(displayIndex, NULL);
    643
    644    return _this->displays[displayIndex].driverdata;
    645}
    646
    647const char *
    648SDL_GetDisplayName(int displayIndex)
    649{
    650    CHECK_DISPLAY_INDEX(displayIndex, NULL);
    651
    652    return _this->displays[displayIndex].name;
    653}
    654
    655int
    656SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
    657{
    658    CHECK_DISPLAY_INDEX(displayIndex, -1);
    659
    660    if (rect) {
    661        SDL_VideoDisplay *display = &_this->displays[displayIndex];
    662
    663        if (_this->GetDisplayBounds) {
    664            if (_this->GetDisplayBounds(_this, display, rect) == 0) {
    665                return 0;
    666            }
    667        }
    668
    669        /* Assume that the displays are left to right */
    670        if (displayIndex == 0) {
    671            rect->x = 0;
    672            rect->y = 0;
    673        } else {
    674            SDL_GetDisplayBounds(displayIndex-1, rect);
    675            rect->x += rect->w;
    676        }
    677        rect->w = display->current_mode.w;
    678        rect->h = display->current_mode.h;
    679    }
    680    return 0;
    681}
    682
    683SDL_bool
    684SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
    685{
    686    SDL_DisplayMode *modes;
    687    int i, nmodes;
    688
    689    /* Make sure we don't already have the mode in the list */
    690    modes = display->display_modes;
    691    nmodes = display->num_display_modes;
    692    for (i = 0; i < nmodes; ++i) {
    693        if (cmpmodes(mode, &modes[i]) == 0) {
    694            return SDL_FALSE;
    695        }
    696    }
    697
    698    /* Go ahead and add the new mode */
    699    if (nmodes == display->max_display_modes) {
    700        modes =
    701            SDL_realloc(modes,
    702                        (display->max_display_modes + 32) * sizeof(*modes));
    703        if (!modes) {
    704            return SDL_FALSE;
    705        }
    706        display->display_modes = modes;
    707        display->max_display_modes += 32;
    708    }
    709    modes[nmodes] = *mode;
    710    display->num_display_modes++;
    711
    712    /* Re-sort video modes */
    713    SDL_qsort(display->display_modes, display->num_display_modes,
    714              sizeof(SDL_DisplayMode), cmpmodes);
    715
    716    return SDL_TRUE;
    717}
    718
    719static int
    720SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
    721{
    722    if (!display->num_display_modes && _this->GetDisplayModes) {
    723        _this->GetDisplayModes(_this, display);
    724        SDL_qsort(display->display_modes, display->num_display_modes,
    725                  sizeof(SDL_DisplayMode), cmpmodes);
    726    }
    727    return display->num_display_modes;
    728}
    729
    730int
    731SDL_GetNumDisplayModes(int displayIndex)
    732{
    733    CHECK_DISPLAY_INDEX(displayIndex, -1);
    734
    735    return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
    736}
    737
    738int
    739SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
    740{
    741    SDL_VideoDisplay *display;
    742
    743    CHECK_DISPLAY_INDEX(displayIndex, -1);
    744
    745    display = &_this->displays[displayIndex];
    746    if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
    747        return SDL_SetError("index must be in the range of 0 - %d",
    748                            SDL_GetNumDisplayModesForDisplay(display) - 1);
    749    }
    750    if (mode) {
    751        *mode = display->display_modes[index];
    752    }
    753    return 0;
    754}
    755
    756int
    757SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
    758{
    759    SDL_VideoDisplay *display;
    760
    761    CHECK_DISPLAY_INDEX(displayIndex, -1);
    762
    763    display = &_this->displays[displayIndex];
    764    if (mode) {
    765        *mode = display->desktop_mode;
    766    }
    767    return 0;
    768}
    769
    770int
    771SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
    772{
    773    SDL_VideoDisplay *display;
    774
    775    CHECK_DISPLAY_INDEX(displayIndex, -1);
    776
    777    display = &_this->displays[displayIndex];
    778    if (mode) {
    779        *mode = display->current_mode;
    780    }
    781    return 0;
    782}
    783
    784static SDL_DisplayMode *
    785SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
    786                                    const SDL_DisplayMode * mode,
    787                                    SDL_DisplayMode * closest)
    788{
    789    Uint32 target_format;
    790    int target_refresh_rate;
    791    int i;
    792    SDL_DisplayMode *current, *match;
    793
    794    if (!mode || !closest) {
    795        SDL_SetError("Missing desired mode or closest mode parameter");
    796        return NULL;
    797    }
    798
    799    /* Default to the desktop format */
    800    if (mode->format) {
    801        target_format = mode->format;
    802    } else {
    803        target_format = display->desktop_mode.format;
    804    }
    805
    806    /* Default to the desktop refresh rate */
    807    if (mode->refresh_rate) {
    808        target_refresh_rate = mode->refresh_rate;
    809    } else {
    810        target_refresh_rate = display->desktop_mode.refresh_rate;
    811    }
    812
    813    match = NULL;
    814    for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
    815        current = &display->display_modes[i];
    816
    817        if (current->w && (current->w < mode->w)) {
    818            /* Out of sorted modes large enough here */
    819            break;
    820        }
    821        if (current->h && (current->h < mode->h)) {
    822            if (current->w && (current->w == mode->w)) {
    823                /* Out of sorted modes large enough here */
    824                break;
    825            }
    826            /* Wider, but not tall enough, due to a different
    827               aspect ratio. This mode must be skipped, but closer
    828               modes may still follow. */
    829            continue;
    830        }
    831        if (!match || current->w < match->w || current->h < match->h) {
    832            match = current;
    833            continue;
    834        }
    835        if (current->format != match->format) {
    836            /* Sorted highest depth to lowest */
    837            if (current->format == target_format ||
    838                (SDL_BITSPERPIXEL(current->format) >=
    839                 SDL_BITSPERPIXEL(target_format)
    840                 && SDL_PIXELTYPE(current->format) ==
    841                 SDL_PIXELTYPE(target_format))) {
    842                match = current;
    843            }
    844            continue;
    845        }
    846        if (current->refresh_rate != match->refresh_rate) {
    847            /* Sorted highest refresh to lowest */
    848            if (current->refresh_rate >= target_refresh_rate) {
    849                match = current;
    850            }
    851        }
    852    }
    853    if (match) {
    854        if (match->format) {
    855            closest->format = match->format;
    856        } else {
    857            closest->format = mode->format;
    858        }
    859        if (match->w && match->h) {
    860            closest->w = match->w;
    861            closest->h = match->h;
    862        } else {
    863            closest->w = mode->w;
    864            closest->h = mode->h;
    865        }
    866        if (match->refresh_rate) {
    867            closest->refresh_rate = match->refresh_rate;
    868        } else {
    869            closest->refresh_rate = mode->refresh_rate;
    870        }
    871        closest->driverdata = match->driverdata;
    872
    873        /*
    874         * Pick some reasonable defaults if the app and driver don't
    875         * care
    876         */
    877        if (!closest->format) {
    878            closest->format = SDL_PIXELFORMAT_RGB888;
    879        }
    880        if (!closest->w) {
    881            closest->w = 640;
    882        }
    883        if (!closest->h) {
    884            closest->h = 480;
    885        }
    886        return closest;
    887    }
    888    return NULL;
    889}
    890
    891SDL_DisplayMode *
    892SDL_GetClosestDisplayMode(int displayIndex,
    893                          const SDL_DisplayMode * mode,
    894                          SDL_DisplayMode * closest)
    895{
    896    SDL_VideoDisplay *display;
    897
    898    CHECK_DISPLAY_INDEX(displayIndex, NULL);
    899
    900    display = &_this->displays[displayIndex];
    901    return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
    902}
    903
    904static int
    905SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
    906{
    907    SDL_DisplayMode display_mode;
    908    SDL_DisplayMode current_mode;
    909
    910    if (mode) {
    911        display_mode = *mode;
    912
    913        /* Default to the current mode */
    914        if (!display_mode.format) {
    915            display_mode.format = display->current_mode.format;
    916        }
    917        if (!display_mode.w) {
    918            display_mode.w = display->current_mode.w;
    919        }
    920        if (!display_mode.h) {
    921            display_mode.h = display->current_mode.h;
    922        }
    923        if (!display_mode.refresh_rate) {
    924            display_mode.refresh_rate = display->current_mode.refresh_rate;
    925        }
    926
    927        /* Get a good video mode, the closest one possible */
    928        if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
    929            return SDL_SetError("No video mode large enough for %dx%d",
    930                                display_mode.w, display_mode.h);
    931        }
    932    } else {
    933        display_mode = display->desktop_mode;
    934    }
    935
    936    /* See if there's anything left to do */
    937    current_mode = display->current_mode;
    938    if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
    939        return 0;
    940    }
    941
    942    /* Actually change the display mode */
    943    if (!_this->SetDisplayMode) {
    944        return SDL_SetError("Video driver doesn't support changing display mode");
    945    }
    946    if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
    947        return -1;
    948    }
    949    display->current_mode = display_mode;
    950    return 0;
    951}
    952
    953int
    954SDL_GetWindowDisplayIndex(SDL_Window * window)
    955{
    956    int displayIndex;
    957    int i, dist;
    958    int closest = -1;
    959    int closest_dist = 0x7FFFFFFF;
    960    SDL_Point center;
    961    SDL_Point delta;
    962    SDL_Rect rect;
    963
    964    CHECK_WINDOW_MAGIC(window, -1);
    965
    966    if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
    967        SDL_WINDOWPOS_ISCENTERED(window->x)) {
    968        displayIndex = (window->x & 0xFFFF);
    969        if (displayIndex >= _this->num_displays) {
    970            displayIndex = 0;
    971        }
    972        return displayIndex;
    973    }
    974    if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
    975        SDL_WINDOWPOS_ISCENTERED(window->y)) {
    976        displayIndex = (window->y & 0xFFFF);
    977        if (displayIndex >= _this->num_displays) {
    978            displayIndex = 0;
    979        }
    980        return displayIndex;
    981    }
    982
    983    /* Find the display containing the window */
    984    for (i = 0; i < _this->num_displays; ++i) {
    985        SDL_VideoDisplay *display = &_this->displays[i];
    986
    987        if (display->fullscreen_window == window) {
    988            return i;
    989        }
    990    }
    991    center.x = window->x + window->w / 2;
    992    center.y = window->y + window->h / 2;
    993    for (i = 0; i < _this->num_displays; ++i) {
    994        SDL_GetDisplayBounds(i, &rect);
    995        if (SDL_EnclosePoints(&center, 1, &rect, NULL)) {
    996            return i;
    997        }
    998
    999        delta.x = center.x - (rect.x + rect.w / 2);
   1000        delta.y = center.y - (rect.y + rect.h / 2);
   1001        dist = (delta.x*delta.x + delta.y*delta.y);
   1002        if (dist < closest_dist) {
   1003            closest = i;
   1004            closest_dist = dist;
   1005        }
   1006    }
   1007    if (closest < 0) {
   1008        SDL_SetError("Couldn't find any displays");
   1009    }
   1010    return closest;
   1011}
   1012
   1013SDL_VideoDisplay *
   1014SDL_GetDisplayForWindow(SDL_Window *window)
   1015{
   1016    int displayIndex = SDL_GetWindowDisplayIndex(window);
   1017    if (displayIndex >= 0) {
   1018        return &_this->displays[displayIndex];
   1019    } else {
   1020        return NULL;
   1021    }
   1022}
   1023
   1024int
   1025SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   1026{
   1027    CHECK_WINDOW_MAGIC(window, -1);
   1028
   1029    if (mode) {
   1030        window->fullscreen_mode = *mode;
   1031    } else {
   1032        SDL_zero(window->fullscreen_mode);
   1033    }
   1034
   1035    if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   1036        SDL_DisplayMode fullscreen_mode;
   1037        if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
   1038            SDL_SetDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode);
   1039        }
   1040    }
   1041    return 0;
   1042}
   1043
   1044int
   1045SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
   1046{
   1047    SDL_DisplayMode fullscreen_mode;
   1048    SDL_VideoDisplay *display;
   1049
   1050    CHECK_WINDOW_MAGIC(window, -1);
   1051
   1052    if (!mode) {
   1053        return SDL_InvalidParamError("mode");
   1054    }
   1055
   1056    fullscreen_mode = window->fullscreen_mode;
   1057    if (!fullscreen_mode.w) {
   1058        fullscreen_mode.w = window->windowed.w;
   1059    }
   1060    if (!fullscreen_mode.h) {
   1061        fullscreen_mode.h = window->windowed.h;
   1062    }
   1063
   1064    display = SDL_GetDisplayForWindow(window);
   1065
   1066    /* if in desktop size mode, just return the size of the desktop */
   1067    if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   1068        fullscreen_mode = display->desktop_mode;
   1069    } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
   1070                                             &fullscreen_mode,
   1071                                             &fullscreen_mode)) {
   1072        return SDL_SetError("Couldn't find display mode match");
   1073    }
   1074
   1075    if (mode) {
   1076        *mode = fullscreen_mode;
   1077    }
   1078    return 0;
   1079}
   1080
   1081Uint32
   1082SDL_GetWindowPixelFormat(SDL_Window * window)
   1083{
   1084    SDL_VideoDisplay *display;
   1085
   1086    CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
   1087
   1088    display = SDL_GetDisplayForWindow(window);
   1089    return display->current_mode.format;
   1090}
   1091
   1092static void
   1093SDL_RestoreMousePosition(SDL_Window *window)
   1094{
   1095    int x, y;
   1096
   1097    if (window == SDL_GetMouseFocus()) {
   1098        SDL_GetMouseState(&x, &y);
   1099        SDL_WarpMouseInWindow(window, x, y);
   1100    }
   1101}
   1102
   1103static void
   1104SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
   1105{
   1106    SDL_VideoDisplay *display;
   1107    SDL_Window *other;
   1108
   1109    CHECK_WINDOW_MAGIC(window,);
   1110
   1111    /* if we are in the process of hiding don't go back to fullscreen */
   1112    if ( window->is_hiding && fullscreen )
   1113        return;
   1114    
   1115#ifdef __MACOSX__
   1116    if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
   1117        window->last_fullscreen_flags = window->flags;
   1118        return;
   1119    }
   1120#endif
   1121
   1122    display = SDL_GetDisplayForWindow(window);
   1123
   1124    if (fullscreen) {
   1125        /* Hide any other fullscreen windows */
   1126        if (display->fullscreen_window &&
   1127            display->fullscreen_window != window) {
   1128            SDL_MinimizeWindow(display->fullscreen_window);
   1129        }
   1130    }
   1131
   1132    /* See if anything needs to be done now */
   1133    if ((display->fullscreen_window == window) == fullscreen) {
   1134        if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
   1135            return;
   1136        }
   1137    }
   1138
   1139    /* See if there are any fullscreen windows */
   1140    for (other = _this->windows; other; other = other->next) {
   1141        SDL_bool setDisplayMode = SDL_FALSE;
   1142
   1143        if (other == window) {
   1144            setDisplayMode = fullscreen;
   1145        } else if (FULLSCREEN_VISIBLE(other) &&
   1146                   SDL_GetDisplayForWindow(other) == display) {
   1147            setDisplayMode = SDL_TRUE;
   1148        }
   1149
   1150        if (setDisplayMode) {
   1151            SDL_DisplayMode fullscreen_mode;
   1152
   1153            SDL_zero(fullscreen_mode);
   1154
   1155            if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
   1156                SDL_bool resized = SDL_TRUE;
   1157
   1158                if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
   1159                    resized = SDL_FALSE;
   1160                }
   1161
   1162                /* only do the mode change if we want exclusive fullscreen */
   1163                if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   1164                    SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
   1165                } else {
   1166                    SDL_SetDisplayModeForDisplay(display, NULL);
   1167                }
   1168
   1169                if (_this->SetWindowFullscreen) {
   1170                    _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
   1171                }
   1172                display->fullscreen_window = other;
   1173
   1174                /* Generate a mode change event here */
   1175                if (resized) {
   1176                    SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
   1177                                        fullscreen_mode.w, fullscreen_mode.h);
   1178                } else {
   1179                    SDL_OnWindowResized(other);
   1180                }
   1181
   1182                SDL_RestoreMousePosition(other);
   1183
   1184                window->last_fullscreen_flags = window->flags;
   1185                return;
   1186            }
   1187        }
   1188    }
   1189
   1190    /* Nope, restore the desktop mode */
   1191    SDL_SetDisplayModeForDisplay(display, NULL);
   1192
   1193    if (_this->SetWindowFullscreen) {
   1194        _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
   1195    }
   1196    display->fullscreen_window = NULL;
   1197
   1198    /* Generate a mode change event here */
   1199    SDL_OnWindowResized(window);
   1200
   1201    /* Restore the cursor position */
   1202    SDL_RestoreMousePosition(window);
   1203
   1204    window->last_fullscreen_flags = window->flags;
   1205}
   1206
   1207#define CREATE_FLAGS \
   1208    (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
   1209
   1210static void
   1211SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
   1212{
   1213    window->windowed.x = window->x;
   1214    window->windowed.y = window->y;
   1215    window->windowed.w = window->w;
   1216    window->windowed.h = window->h;
   1217
   1218    if (flags & SDL_WINDOW_MAXIMIZED) {
   1219        SDL_MaximizeWindow(window);
   1220    }
   1221    if (flags & SDL_WINDOW_MINIMIZED) {
   1222        SDL_MinimizeWindow(window);
   1223    }
   1224    if (flags & SDL_WINDOW_FULLSCREEN) {
   1225        SDL_SetWindowFullscreen(window, flags);
   1226    }
   1227    if (flags & SDL_WINDOW_INPUT_GRABBED) {
   1228        SDL_SetWindowGrab(window, SDL_TRUE);
   1229    }
   1230    if (!(flags & SDL_WINDOW_HIDDEN)) {
   1231        SDL_ShowWindow(window);
   1232    }
   1233}
   1234
   1235SDL_Window *
   1236SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
   1237{
   1238    SDL_Window *window;
   1239    const char *hint;
   1240
   1241    if (!_this) {
   1242        /* Initialize the video system if needed */
   1243        if (SDL_VideoInit(NULL) < 0) {
   1244            return NULL;
   1245        }
   1246    }
   1247
   1248    /* Some platforms can't create zero-sized windows */
   1249    if (w < 1) {
   1250        w = 1;
   1251    }
   1252    if (h < 1) {
   1253        h = 1;
   1254    }
   1255
   1256    /* Some platforms have OpenGL enabled by default */
   1257#if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
   1258    flags |= SDL_WINDOW_OPENGL;
   1259#endif
   1260    if (flags & SDL_WINDOW_OPENGL) {
   1261        if (!_this->GL_CreateContext) {
   1262            SDL_SetError("No OpenGL support in video driver");
   1263            return NULL;
   1264        }
   1265        if (SDL_GL_LoadLibrary(NULL) < 0) {
   1266            return NULL;
   1267        }
   1268    }
   1269
   1270    /* Unless the user has specified the high-DPI disabling hint, respect the
   1271     * SDL_WINDOW_ALLOW_HIGHDPI flag.
   1272     */
   1273    if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
   1274        hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
   1275        if (hint && SDL_atoi(hint) > 0) {
   1276            flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
   1277        }
   1278    }
   1279
   1280    window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
   1281    if (!window) {
   1282        SDL_OutOfMemory();
   1283        return NULL;
   1284    }
   1285    window->magic = &_this->window_magic;
   1286    window->id = _this->next_object_id++;
   1287    window->x = x;
   1288    window->y = y;
   1289    window->w = w;
   1290    window->h = h;
   1291    if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
   1292        SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
   1293        SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   1294        int displayIndex;
   1295        SDL_Rect bounds;
   1296
   1297        displayIndex = SDL_GetIndexOfDisplay(display);
   1298        SDL_GetDisplayBounds(displayIndex, &bounds);
   1299        if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
   1300            window->x = bounds.x + (bounds.w - w) / 2;
   1301        }
   1302        if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
   1303            window->y = bounds.y + (bounds.h - h) / 2;
   1304        }
   1305    }
   1306    window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
   1307    window->last_fullscreen_flags = window->flags;
   1308    window->brightness = 1.0f;
   1309    window->next = _this->windows;
   1310    window->is_destroying = SDL_FALSE;
   1311
   1312    if (_this->windows) {
   1313        _this->windows->prev = window;
   1314    }
   1315    _this->windows = window;
   1316
   1317    if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
   1318        SDL_DestroyWindow(window);
   1319        return NULL;
   1320    }
   1321
   1322    if (title) {
   1323        SDL_SetWindowTitle(window, title);
   1324    }
   1325    SDL_FinishWindowCreation(window, flags);
   1326
   1327    /* If the window was created fullscreen, make sure the mode code matches */
   1328    SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
   1329
   1330    return window;
   1331}
   1332
   1333SDL_Window *
   1334SDL_CreateWindowFrom(const void *data)
   1335{
   1336    SDL_Window *window;
   1337
   1338    if (!_this) {
   1339        SDL_UninitializedVideo();
   1340        return NULL;
   1341    }
   1342    if (!_this->CreateWindowFrom) {
   1343        SDL_Unsupported();
   1344        return NULL;
   1345    }
   1346    window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
   1347    if (!window) {
   1348        SDL_OutOfMemory();
   1349        return NULL;
   1350    }
   1351    window->magic = &_this->window_magic;
   1352    window->id = _this->next_object_id++;
   1353    window->flags = SDL_WINDOW_FOREIGN;
   1354    window->last_fullscreen_flags = window->flags;
   1355    window->is_destroying = SDL_FALSE;
   1356    window->brightness = 1.0f;
   1357    window->next = _this->windows;
   1358    if (_this->windows) {
   1359        _this->windows->prev = window;
   1360    }
   1361    _this->windows = window;
   1362
   1363    if (_this->CreateWindowFrom(_this, window, data) < 0) {
   1364        SDL_DestroyWindow(window);
   1365        return NULL;
   1366    }
   1367    return window;
   1368}
   1369
   1370int
   1371SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
   1372{
   1373    char *title = window->title;
   1374    SDL_Surface *icon = window->icon;
   1375    SDL_bool loaded_opengl = SDL_FALSE;
   1376
   1377    if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
   1378        return SDL_SetError("No OpenGL support in video driver");
   1379    }
   1380
   1381    if (window->flags & SDL_WINDOW_FOREIGN) {
   1382        /* Can't destroy and re-create foreign windows, hrm */
   1383        flags |= SDL_WINDOW_FOREIGN;
   1384    } else {
   1385        flags &= ~SDL_WINDOW_FOREIGN;
   1386    }
   1387
   1388    /* Restore video mode, etc. */
   1389    SDL_HideWindow(window);
   1390
   1391    /* Tear down the old native window */
   1392    if (window->surface) {
   1393        window->surface->flags &= ~SDL_DONTFREE;
   1394        SDL_FreeSurface(window->surface);
   1395    }
   1396    if (_this->DestroyWindowFramebuffer) {
   1397        _this->DestroyWindowFramebuffer(_this, window);
   1398    }
   1399    if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
   1400        _this->DestroyWindow(_this, window);
   1401    }
   1402
   1403    if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
   1404        if (flags & SDL_WINDOW_OPENGL) {
   1405            if (SDL_GL_LoadLibrary(NULL) < 0) {
   1406                return -1;
   1407            }
   1408            loaded_opengl = SDL_TRUE;
   1409        } else {
   1410            SDL_GL_UnloadLibrary();
   1411        }
   1412    }
   1413
   1414    window->title = NULL;
   1415    window->icon = NULL;
   1416    window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
   1417    window->last_fullscreen_flags = window->flags;
   1418    window->is_destroying = SDL_FALSE;
   1419
   1420    if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
   1421        if (_this->CreateWindow(_this, window) < 0) {
   1422            if (loaded_opengl) {
   1423                SDL_GL_UnloadLibrary();
   1424                window->flags &= ~SDL_WINDOW_OPENGL;
   1425            }
   1426            return -1;
   1427        }
   1428    }
   1429    if (flags & SDL_WINDOW_FOREIGN) {
   1430        window->flags |= SDL_WINDOW_FOREIGN;
   1431    }
   1432
   1433    if (title) {
   1434        SDL_SetWindowTitle(window, title);
   1435        SDL_free(title);
   1436    }
   1437    if (icon) {
   1438        SDL_SetWindowIcon(window, icon);
   1439        SDL_FreeSurface(icon);
   1440    }
   1441
   1442    if (window->hit_test) {
   1443        _this->SetWindowHitTest(window, SDL_TRUE);
   1444    }
   1445
   1446    SDL_FinishWindowCreation(window, flags);
   1447
   1448    return 0;
   1449}
   1450
   1451Uint32
   1452SDL_GetWindowID(SDL_Window * window)
   1453{
   1454    CHECK_WINDOW_MAGIC(window, 0);
   1455
   1456    return window->id;
   1457}
   1458
   1459SDL_Window *
   1460SDL_GetWindowFromID(Uint32 id)
   1461{
   1462    SDL_Window *window;
   1463
   1464    if (!_this) {
   1465        return NULL;
   1466    }
   1467    for (window = _this->windows; window; window = window->next) {
   1468        if (window->id == id) {
   1469            return window;
   1470        }
   1471    }
   1472    return NULL;
   1473}
   1474
   1475Uint32
   1476SDL_GetWindowFlags(SDL_Window * window)
   1477{
   1478    CHECK_WINDOW_MAGIC(window, 0);
   1479
   1480    return window->flags;
   1481}
   1482
   1483void
   1484SDL_SetWindowTitle(SDL_Window * window, const char *title)
   1485{
   1486    CHECK_WINDOW_MAGIC(window,);
   1487
   1488    if (title == window->title) {
   1489        return;
   1490    }
   1491    SDL_free(window->title);
   1492    if (title && *title) {
   1493        window->title = SDL_strdup(title);
   1494    } else {
   1495        window->title = NULL;
   1496    }
   1497
   1498    if (_this->SetWindowTitle) {
   1499        _this->SetWindowTitle(_this, window);
   1500    }
   1501}
   1502
   1503const char *
   1504SDL_GetWindowTitle(SDL_Window * window)
   1505{
   1506    CHECK_WINDOW_MAGIC(window, "");
   1507
   1508    return window->title ? window->title : "";
   1509}
   1510
   1511void
   1512SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
   1513{
   1514    CHECK_WINDOW_MAGIC(window,);
   1515
   1516    if (!icon) {
   1517        return;
   1518    }
   1519
   1520    SDL_FreeSurface(window->icon);
   1521
   1522    /* Convert the icon into ARGB8888 */
   1523    window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
   1524    if (!window->icon) {
   1525        return;
   1526    }
   1527
   1528    if (_this->SetWindowIcon) {
   1529        _this->SetWindowIcon(_this, window, window->icon);
   1530    }
   1531}
   1532
   1533void*
   1534SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
   1535{
   1536    SDL_WindowUserData *prev, *data;
   1537
   1538    CHECK_WINDOW_MAGIC(window, NULL);
   1539
   1540    /* Input validation */
   1541    if (name == NULL || name[0] == '\0') {
   1542      SDL_InvalidParamError("name");
   1543      return NULL;
   1544    }
   1545
   1546    /* See if the named data already exists */
   1547    prev = NULL;
   1548    for (data = window->data; data; prev = data, data = data->next) {
   1549        if (data->name && SDL_strcmp(data->name, name) == 0) {
   1550            void *last_value = data->data;
   1551
   1552            if (userdata) {
   1553                /* Set the new value */
   1554                data->data = userdata;
   1555            } else {
   1556                /* Delete this value */
   1557                if (prev) {
   1558                    prev->next = data->next;
   1559                } else {
   1560                    window->data = data->next;
   1561                }
   1562                SDL_free(data->name);
   1563                SDL_free(data);
   1564            }
   1565            return last_value;
   1566        }
   1567    }
   1568
   1569    /* Add new data to the window */
   1570    if (userdata) {
   1571        data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
   1572        data->name = SDL_strdup(name);
   1573        data->data = userdata;
   1574        data->next = window->data;
   1575        window->data = data;
   1576    }
   1577    return NULL;
   1578}
   1579
   1580void *
   1581SDL_GetWindowData(SDL_Window * window, const char *name)
   1582{
   1583    SDL_WindowUserData *data;
   1584
   1585    CHECK_WINDOW_MAGIC(window, NULL);
   1586
   1587    /* Input validation */
   1588    if (name == NULL || name[0] == '\0') {
   1589      SDL_InvalidParamError("name");
   1590      return NULL;
   1591    }
   1592
   1593    for (data = window->data; data; data = data->next) {
   1594        if (data->name && SDL_strcmp(data->name, name) == 0) {
   1595            return data->data;
   1596        }
   1597    }
   1598    return NULL;
   1599}
   1600
   1601void
   1602SDL_SetWindowPosition(SDL_Window * window, int x, int y)
   1603{
   1604    CHECK_WINDOW_MAGIC(window,);
   1605
   1606    if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
   1607        SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   1608        int displayIndex;
   1609        SDL_Rect bounds;
   1610
   1611        SDL_zero(bounds);
   1612
   1613        displayIndex = SDL_GetIndexOfDisplay(display);
   1614        SDL_GetDisplayBounds(displayIndex, &bounds);
   1615        if (SDL_WINDOWPOS_ISCENTERED(x)) {
   1616            x = bounds.x + (bounds.w - window->w) / 2;
   1617        }
   1618        if (SDL_WINDOWPOS_ISCENTERED(y)) {
   1619            y = bounds.y + (bounds.h - window->h) / 2;
   1620        }
   1621    }
   1622
   1623    if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
   1624        if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
   1625            window->windowed.x = x;
   1626        }
   1627        if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
   1628            window->windowed.y = y;
   1629        }
   1630    } else {
   1631        if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
   1632            window->x = x;
   1633        }
   1634        if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
   1635            window->y = y;
   1636        }
   1637
   1638        if (_this->SetWindowPosition) {
   1639            _this->SetWindowPosition(_this, window);
   1640        }
   1641        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
   1642    }
   1643}
   1644
   1645void
   1646SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
   1647{
   1648    CHECK_WINDOW_MAGIC(window,);
   1649
   1650    /* Fullscreen windows are always at their display's origin */
   1651    if (window->flags & SDL_WINDOW_FULLSCREEN) {
   1652        if (x) {
   1653            *x = 0;
   1654        }
   1655        if (y) {
   1656            *y = 0;
   1657        }
   1658    } else {
   1659        if (x) {
   1660            *x = window->x;
   1661        }
   1662        if (y) {
   1663            *y = window->y;
   1664        }
   1665    }
   1666}
   1667
   1668void
   1669SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
   1670{
   1671    CHECK_WINDOW_MAGIC(window,);
   1672    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   1673        const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
   1674        const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
   1675        if ((want != have) && (_this->SetWindowBordered)) {
   1676            if (want) {
   1677                window->flags &= ~SDL_WINDOW_BORDERLESS;
   1678            } else {
   1679                window->flags |= SDL_WINDOW_BORDERLESS;
   1680            }
   1681            _this->SetWindowBordered(_this, window, (SDL_bool) want);
   1682        }
   1683    }
   1684}
   1685
   1686void
   1687SDL_SetWindowSize(SDL_Window * window, int w, int h)
   1688{
   1689    CHECK_WINDOW_MAGIC(window,);
   1690    if (w <= 0) {
   1691        SDL_InvalidParamError("w");
   1692        return;
   1693    }
   1694    if (h <= 0) {
   1695        SDL_InvalidParamError("h");
   1696        return;
   1697    }
   1698
   1699    /* Make sure we don't exceed any window size limits */
   1700    if (window->min_w && w < window->min_w)
   1701    {
   1702        w = window->min_w;
   1703    }
   1704    if (window->max_w && w > window->max_w)
   1705    {
   1706        w = window->max_w;
   1707    }
   1708    if (window->min_h && h < window->min_h)
   1709    {
   1710        h = window->min_h;
   1711    }
   1712    if (window->max_h && h > window->max_h)
   1713    {
   1714        h = window->max_h;
   1715    }
   1716
   1717    window->windowed.w = w;
   1718    window->windowed.h = h;
   1719
   1720    if (window->flags & SDL_WINDOW_FULLSCREEN) {
   1721        if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   1722            window->last_fullscreen_flags = 0;
   1723            SDL_UpdateFullscreenMode(window, SDL_TRUE);
   1724        }
   1725    } else {
   1726        window->w = w;
   1727        window->h = h;
   1728        if (_this->SetWindowSize) {
   1729            _this->SetWindowSize(_this, window);
   1730        }
   1731        if (window->w == w && window->h == h) {
   1732            /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
   1733            SDL_OnWindowResized(window);
   1734        }
   1735    }
   1736}
   1737
   1738void
   1739SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
   1740{
   1741    CHECK_WINDOW_MAGIC(window,);
   1742    if (w) {
   1743        *w = window->w;
   1744    }
   1745    if (h) {
   1746        *h = window->h;
   1747    }
   1748}
   1749
   1750void
   1751SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
   1752{
   1753    CHECK_WINDOW_MAGIC(window,);
   1754    if (min_w <= 0) {
   1755        SDL_InvalidParamError("min_w");
   1756        return;
   1757    }
   1758    if (min_h <= 0) {
   1759        SDL_InvalidParamError("min_h");
   1760        return;
   1761    }
   1762
   1763    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   1764        window->min_w = min_w;
   1765        window->min_h = min_h;
   1766        if (_this->SetWindowMinimumSize) {
   1767            _this->SetWindowMinimumSize(_this, window);
   1768        }
   1769        /* Ensure that window is not smaller than minimal size */
   1770        SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
   1771    }
   1772}
   1773
   1774void
   1775SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
   1776{
   1777    CHECK_WINDOW_MAGIC(window,);
   1778    if (min_w) {
   1779        *min_w = window->min_w;
   1780    }
   1781    if (min_h) {
   1782        *min_h = window->min_h;
   1783    }
   1784}
   1785
   1786void
   1787SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
   1788{
   1789    CHECK_WINDOW_MAGIC(window,);
   1790    if (max_w <= 0) {
   1791        SDL_InvalidParamError("max_w");
   1792        return;
   1793    }
   1794    if (max_h <= 0) {
   1795        SDL_InvalidParamError("max_h");
   1796        return;
   1797    }
   1798
   1799    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   1800        window->max_w = max_w;
   1801        window->max_h = max_h;
   1802        if (_this->SetWindowMaximumSize) {
   1803            _this->SetWindowMaximumSize(_this, window);
   1804        }
   1805        /* Ensure that window is not larger than maximal size */
   1806        SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
   1807    }
   1808}
   1809
   1810void
   1811SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
   1812{
   1813    CHECK_WINDOW_MAGIC(window,);
   1814    if (max_w) {
   1815        *max_w = window->max_w;
   1816    }
   1817    if (max_h) {
   1818        *max_h = window->max_h;
   1819    }
   1820}
   1821
   1822void
   1823SDL_ShowWindow(SDL_Window * window)
   1824{
   1825    CHECK_WINDOW_MAGIC(window,);
   1826
   1827    if (window->flags & SDL_WINDOW_SHOWN) {
   1828        return;
   1829    }
   1830
   1831    if (_this->ShowWindow) {
   1832        _this->ShowWindow(_this, window);
   1833    }
   1834    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   1835}
   1836
   1837void
   1838SDL_HideWindow(SDL_Window * window)
   1839{
   1840    CHECK_WINDOW_MAGIC(window,);
   1841
   1842    if (!(window->flags & SDL_WINDOW_SHOWN)) {
   1843        return;
   1844    }
   1845
   1846	window->is_hiding = SDL_TRUE;
   1847    SDL_UpdateFullscreenMode(window, SDL_FALSE);
   1848
   1849    if (_this->HideWindow) {
   1850        _this->HideWindow(_this, window);
   1851    }
   1852	window->is_hiding = SDL_FALSE;
   1853    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   1854}
   1855
   1856void
   1857SDL_RaiseWindow(SDL_Window * window)
   1858{
   1859    CHECK_WINDOW_MAGIC(window,);
   1860
   1861    if (!(window->flags & SDL_WINDOW_SHOWN)) {
   1862        return;
   1863    }
   1864    if (_this->RaiseWindow) {
   1865        _this->RaiseWindow(_this, window);
   1866    }
   1867}
   1868
   1869void
   1870SDL_MaximizeWindow(SDL_Window * window)
   1871{
   1872    CHECK_WINDOW_MAGIC(window,);
   1873
   1874    if (window->flags & SDL_WINDOW_MAXIMIZED) {
   1875        return;
   1876    }
   1877
   1878    /* !!! FIXME: should this check if the window is resizable? */
   1879
   1880    if (_this->MaximizeWindow) {
   1881        _this->MaximizeWindow(_this, window);
   1882    }
   1883}
   1884
   1885void
   1886SDL_MinimizeWindow(SDL_Window * window)
   1887{
   1888    CHECK_WINDOW_MAGIC(window,);
   1889
   1890    if (window->flags & SDL_WINDOW_MINIMIZED) {
   1891        return;
   1892    }
   1893
   1894    SDL_UpdateFullscreenMode(window, SDL_FALSE);
   1895
   1896    if (_this->MinimizeWindow) {
   1897        _this->MinimizeWindow(_this, window);
   1898    }
   1899}
   1900
   1901void
   1902SDL_RestoreWindow(SDL_Window * window)
   1903{
   1904    CHECK_WINDOW_MAGIC(window,);
   1905
   1906    if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
   1907        return;
   1908    }
   1909
   1910    if (_this->RestoreWindow) {
   1911        _this->RestoreWindow(_this, window);
   1912    }
   1913}
   1914
   1915int
   1916SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
   1917{
   1918    CHECK_WINDOW_MAGIC(window, -1);
   1919
   1920    flags &= FULLSCREEN_MASK;
   1921
   1922    if (flags == (window->flags & FULLSCREEN_MASK)) {
   1923        return 0;
   1924    }
   1925
   1926    /* clear the previous flags and OR in the new ones */
   1927    window->flags &= ~FULLSCREEN_MASK;
   1928    window->flags |= flags;
   1929
   1930    SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
   1931
   1932    return 0;
   1933}
   1934
   1935static SDL_Surface *
   1936SDL_CreateWindowFramebuffer(SDL_Window * window)
   1937{
   1938    Uint32 format;
   1939    void *pixels;
   1940    int pitch;
   1941    int bpp;
   1942    Uint32 Rmask, Gmask, Bmask, Amask;
   1943
   1944    if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
   1945        return NULL;
   1946    }
   1947
   1948    if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
   1949        return NULL;
   1950    }
   1951
   1952    if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   1953        return NULL;
   1954    }
   1955
   1956    return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
   1957}
   1958
   1959SDL_Surface *
   1960SDL_GetWindowSurface(SDL_Window * window)
   1961{
   1962    CHECK_WINDOW_MAGIC(window, NULL);
   1963
   1964    if (!window->surface_valid) {
   1965        if (window->surface) {
   1966            window->surface->flags &= ~SDL_DONTFREE;
   1967            SDL_FreeSurface(window->surface);
   1968        }
   1969        window->surface = SDL_CreateWindowFramebuffer(window);
   1970        if (window->surface) {
   1971            window->surface_valid = SDL_TRUE;
   1972            window->surface->flags |= SDL_DONTFREE;
   1973        }
   1974    }
   1975    return window->surface;
   1976}
   1977
   1978int
   1979SDL_UpdateWindowSurface(SDL_Window * window)
   1980{
   1981    SDL_Rect full_rect;
   1982
   1983    CHECK_WINDOW_MAGIC(window, -1);
   1984
   1985    full_rect.x = 0;
   1986    full_rect.y = 0;
   1987    full_rect.w = window->w;
   1988    full_rect.h = window->h;
   1989    return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
   1990}
   1991
   1992int
   1993SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
   1994                             int numrects)
   1995{
   1996    CHECK_WINDOW_MAGIC(window, -1);
   1997
   1998    if (!window->surface_valid) {
   1999        return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
   2000    }
   2001
   2002    return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
   2003}
   2004
   2005int
   2006SDL_SetWindowBrightness(SDL_Window * window, float brightness)
   2007{
   2008    Uint16 ramp[256];
   2009    int status;
   2010
   2011    CHECK_WINDOW_MAGIC(window, -1);
   2012
   2013    SDL_CalculateGammaRamp(brightness, ramp);
   2014    status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
   2015    if (status == 0) {
   2016        window->brightness = brightness;
   2017    }
   2018    return status;
   2019}
   2020
   2021float
   2022SDL_GetWindowBrightness(SDL_Window * window)
   2023{
   2024    CHECK_WINDOW_MAGIC(window, 1.0f);
   2025
   2026    return window->brightness;
   2027}
   2028
   2029int
   2030SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
   2031                                            const Uint16 * green,
   2032                                            const Uint16 * blue)
   2033{
   2034    CHECK_WINDOW_MAGIC(window, -1);
   2035
   2036    if (!_this->SetWindowGammaRamp) {
   2037        return SDL_Unsupported();
   2038    }
   2039
   2040    if (!window->gamma) {
   2041        if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
   2042            return -1;
   2043        }
   2044    }
   2045
   2046    if (red) {
   2047        SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
   2048    }
   2049    if (green) {
   2050        SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
   2051    }
   2052    if (blue) {
   2053        SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
   2054    }
   2055    if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
   2056        return _this->SetWindowGammaRamp(_this, window, window->gamma);
   2057    } else {
   2058        return 0;
   2059    }
   2060}
   2061
   2062int
   2063SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
   2064                                            Uint16 * green,
   2065                                            Uint16 * blue)
   2066{
   2067    CHECK_WINDOW_MAGIC(window, -1);
   2068
   2069    if (!window->gamma) {
   2070        int i;
   2071
   2072        window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
   2073        if (!window->gamma) {
   2074            return SDL_OutOfMemory();
   2075        }
   2076        window->saved_gamma = window->gamma + 3*256;
   2077
   2078        if (_this->GetWindowGammaRamp) {
   2079            if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
   2080                return -1;
   2081            }
   2082        } else {
   2083            /* Create an identity gamma ramp */
   2084            for (i = 0; i < 256; ++i) {
   2085                Uint16 value = (Uint16)((i << 8) | i);
   2086
   2087                window->gamma[0*256+i] = value;
   2088                window->gamma[1*256+i] = value;
   2089                window->gamma[2*256+i] = value;
   2090            }
   2091        }
   2092        SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
   2093    }
   2094
   2095    if (red) {
   2096        SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
   2097    }
   2098    if (green) {
   2099        SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
   2100    }
   2101    if (blue) {
   2102        SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
   2103    }
   2104    return 0;
   2105}
   2106
   2107void
   2108SDL_UpdateWindowGrab(SDL_Window * window)
   2109{
   2110    if (_this->SetWindowGrab) {
   2111        SDL_bool grabbed;
   2112        if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   2113             (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   2114            grabbed = SDL_TRUE;
   2115        } else {
   2116            grabbed = SDL_FALSE;
   2117        }
   2118        _this->SetWindowGrab(_this, window, grabbed);
   2119    }
   2120}
   2121
   2122void
   2123SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
   2124{
   2125    CHECK_WINDOW_MAGIC(window,);
   2126
   2127    if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
   2128        return;
   2129    }
   2130    if (grabbed) {
   2131        window->flags |= SDL_WINDOW_INPUT_GRABBED;
   2132    } else {
   2133        window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
   2134    }
   2135    SDL_UpdateWindowGrab(window);
   2136}
   2137
   2138SDL_bool
   2139SDL_GetWindowGrab(SDL_Window * window)
   2140{
   2141    CHECK_WINDOW_MAGIC(window, SDL_FALSE);
   2142
   2143    return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
   2144}
   2145
   2146void
   2147SDL_OnWindowShown(SDL_Window * window)
   2148{
   2149    SDL_OnWindowRestored(window);
   2150}
   2151
   2152void
   2153SDL_OnWindowHidden(SDL_Window * window)
   2154{
   2155    SDL_UpdateFullscreenMode(window, SDL_FALSE);
   2156}
   2157
   2158void
   2159SDL_OnWindowResized(SDL_Window * window)
   2160{
   2161    window->surface_valid = SDL_FALSE;
   2162    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
   2163}
   2164
   2165void
   2166SDL_OnWindowMinimized(SDL_Window * window)
   2167{
   2168    SDL_UpdateFullscreenMode(window, SDL_FALSE);
   2169}
   2170
   2171void
   2172SDL_OnWindowRestored(SDL_Window * window)
   2173{
   2174    /*
   2175     * FIXME: Is this fine to just remove this, or should it be preserved just
   2176     * for the fullscreen case? In principle it seems like just hiding/showing
   2177     * windows shouldn't affect the stacking order; maybe the right fix is to
   2178     * re-decouple OnWindowShown and OnWindowRestored.
   2179     */
   2180    /*SDL_RaiseWindow(window);*/
   2181
   2182    if (FULLSCREEN_VISIBLE(window)) {
   2183        SDL_UpdateFullscreenMode(window, SDL_TRUE);
   2184    }
   2185}
   2186
   2187void
   2188SDL_OnWindowEnter(SDL_Window * window)
   2189{
   2190    if (_this->OnWindowEnter) {
   2191        _this->OnWindowEnter(_this, window);
   2192    }
   2193}
   2194
   2195void
   2196SDL_OnWindowLeave(SDL_Window * window)
   2197{
   2198}
   2199
   2200void
   2201SDL_OnWindowFocusGained(SDL_Window * window)
   2202{
   2203    SDL_Mouse *mouse = SDL_GetMouse();
   2204
   2205    if (window->gamma && _this->SetWindowGammaRamp) {
   2206        _this->SetWindowGammaRamp(_this, window, window->gamma);
   2207    }
   2208
   2209    if (mouse && mouse->relative_mode) {
   2210        SDL_SetMouseFocus(window);
   2211        SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
   2212    }
   2213
   2214    SDL_UpdateWindowGrab(window);
   2215}
   2216
   2217static SDL_bool
   2218ShouldMinimizeOnFocusLoss(SDL_Window * window)
   2219{
   2220    const char *hint;
   2221
   2222    if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
   2223        return SDL_FALSE;
   2224    }
   2225
   2226#ifdef __MACOSX__
   2227    if (Cocoa_IsWindowInFullscreenSpace(window)) {
   2228        return SDL_FALSE;
   2229    }
   2230#endif
   2231
   2232    hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
   2233    if (hint) {
   2234        if (*hint == '0') {
   2235            return SDL_FALSE;
   2236        } else {
   2237            return SDL_TRUE;
   2238        }
   2239    }
   2240
   2241    return SDL_TRUE;
   2242}
   2243
   2244void
   2245SDL_OnWindowFocusLost(SDL_Window * window)
   2246{
   2247    if (window->gamma && _this->SetWindowGammaRamp) {
   2248        _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
   2249    }
   2250
   2251    SDL_UpdateWindowGrab(window);
   2252
   2253    if (ShouldMinimizeOnFocusLoss(window)) {
   2254        SDL_MinimizeWindow(window);
   2255    }
   2256}
   2257
   2258/* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
   2259   !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
   2260SDL_Window *
   2261SDL_GetFocusWindow(void)
   2262{
   2263    SDL_Window *window;
   2264
   2265    if (!_this) {
   2266        return NULL;
   2267    }
   2268    for (window = _this->windows; window; window = window->next) {
   2269        if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
   2270            return window;
   2271        }
   2272    }
   2273    return NULL;
   2274}
   2275
   2276void
   2277SDL_DestroyWindow(SDL_Window * window)
   2278{
   2279    SDL_VideoDisplay *display;
   2280
   2281    CHECK_WINDOW_MAGIC(window,);
   2282
   2283    window->is_destroying = SDL_TRUE;
   2284
   2285    /* Restore video mode, etc. */
   2286    SDL_HideWindow(window);
   2287
   2288    /* Make sure this window no longer has focus */
   2289    if (SDL_GetKeyboardFocus() == window) {
   2290        SDL_SetKeyboardFocus(NULL);
   2291    }
   2292    if (SDL_GetMouseFocus() == window) {
   2293        SDL_SetMouseFocus(NULL);
   2294    }
   2295
   2296    /* make no context current if this is the current context window. */
   2297    if (window->flags & SDL_WINDOW_OPENGL) {
   2298        if (_this->current_glwin == window) {
   2299            SDL_GL_MakeCurrent(window, NULL);
   2300        }
   2301    }
   2302
   2303    if (window->surface) {
   2304        window->surface->flags &= ~SDL_DONTFREE;
   2305        SDL_FreeSurface(window->surface);
   2306    }
   2307    if (_this->DestroyWindowFramebuffer) {
   2308        _this->DestroyWindowFramebuffer(_this, window);
   2309    }
   2310    if (_this->DestroyWindow) {
   2311        _this->DestroyWindow(_this, window);
   2312    }
   2313    if (window->flags & SDL_WINDOW_OPENGL) {
   2314        SDL_GL_UnloadLibrary();
   2315    }
   2316
   2317    display = SDL_GetDisplayForWindow(window);
   2318    if (display->fullscreen_window == window) {
   2319        display->fullscreen_window = NULL;
   2320    }
   2321
   2322    /* Now invalidate magic */
   2323    window->magic = NULL;
   2324
   2325    /* Free memory associated with the window */
   2326    SDL_free(window->title);
   2327    SDL_FreeSurface(window->icon);
   2328    SDL_free(window->gamma);
   2329    while (window->data) {
   2330        SDL_WindowUserData *data = window->data;
   2331
   2332        window->data = data->next;
   2333        SDL_free(data->name);
   2334        SDL_free(data);
   2335    }
   2336
   2337    /* Unlink the window from the list */
   2338    if (window->next) {
   2339        window->next->prev = window->prev;
   2340    }
   2341    if (window->prev) {
   2342        window->prev->next = window->next;
   2343    } else {
   2344        _this->windows = window->next;
   2345    }
   2346
   2347    SDL_free(window);
   2348}
   2349
   2350SDL_bool
   2351SDL_IsScreenSaverEnabled()
   2352{
   2353    if (!_this) {
   2354        return SDL_TRUE;
   2355    }
   2356    return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
   2357}
   2358
   2359void
   2360SDL_EnableScreenSaver()
   2361{
   2362    if (!_this) {
   2363        return;
   2364    }
   2365    if (!_this->suspend_screensaver) {
   2366        return;
   2367    }
   2368    _this->suspend_screensaver = SDL_FALSE;
   2369    if (_this->SuspendScreenSaver) {
   2370        _this->SuspendScreenSaver(_this);
   2371    }
   2372}
   2373
   2374void
   2375SDL_DisableScreenSaver()
   2376{
   2377    if (!_this) {
   2378        return;
   2379    }
   2380    if (_this->suspend_screensaver) {
   2381        return;
   2382    }
   2383    _this->suspend_screensaver = SDL_TRUE;
   2384    if (_this->SuspendScreenSaver) {
   2385        _this->SuspendScreenSaver(_this);
   2386    }
   2387}
   2388
   2389void
   2390SDL_VideoQuit(void)
   2391{
   2392    int i, j;
   2393
   2394    if (!_this) {
   2395        return;
   2396    }
   2397
   2398    /* Halt event processing before doing anything else */
   2399    SDL_TouchQuit();
   2400    SDL_MouseQuit();
   2401    SDL_KeyboardQuit();
   2402    SDL_QuitSubSystem(SDL_INIT_EVENTS);
   2403
   2404    SDL_EnableScreenSaver();
   2405
   2406    /* Clean up the system video */
   2407    while (_this->windows) {
   2408        SDL_DestroyWindow(_this->windows);
   2409    }
   2410    _this->VideoQuit(_this);
   2411
   2412    for (i = 0; i < _this->num_displays; ++i) {
   2413        SDL_VideoDisplay *display = &_this->displays[i];
   2414        for (j = display->num_display_modes; j--;) {
   2415            SDL_free(display->display_modes[j].driverdata);
   2416            display->display_modes[j].driverdata = NULL;
   2417        }
   2418        SDL_free(display->display_modes);
   2419        display->display_modes = NULL;
   2420        SDL_free(display->desktop_mode.driverdata);
   2421        display->desktop_mode.driverdata = NULL;
   2422        SDL_free(display->driverdata);
   2423        display->driverdata = NULL;
   2424    }
   2425    if (_this->displays) {
   2426        for (i = 0; i < _this->num_displays; ++i) {
   2427            SDL_free(_this->displays[i].name);
   2428        }
   2429        SDL_free(_this->displays);
   2430        _this->displays = NULL;
   2431        _this->num_displays = 0;
   2432    }
   2433    SDL_free(_this->clipboard_text);
   2434    _this->clipboard_text = NULL;
   2435    _this->free(_this);
   2436    _this = NULL;
   2437}
   2438
   2439int
   2440SDL_GL_LoadLibrary(const char *path)
   2441{
   2442    int retval;
   2443
   2444    if (!_this) {
   2445        return SDL_UninitializedVideo();
   2446    }
   2447    if (_this->gl_config.driver_loaded) {
   2448        if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
   2449            return SDL_SetError("OpenGL library already loaded");
   2450        }
   2451        retval = 0;
   2452    } else {
   2453        if (!_this->GL_LoadLibrary) {
   2454            return SDL_SetError("No dynamic GL support in video driver");
   2455        }
   2456        retval = _this->GL_LoadLibrary(_this, path);
   2457    }
   2458    if (retval == 0) {
   2459        ++_this->gl_config.driver_loaded;
   2460    } else {
   2461        if (_this->GL_UnloadLibrary) {
   2462            _this->GL_UnloadLibrary(_this);
   2463        }
   2464    }
   2465    return (retval);
   2466}
   2467
   2468void *
   2469SDL_GL_GetProcAddress(const char *proc)
   2470{
   2471    void *func;
   2472
   2473    if (!_this) {
   2474        SDL_UninitializedVideo();
   2475        return NULL;
   2476    }
   2477    func = NULL;
   2478    if (_this->GL_GetProcAddress) {
   2479        if (_this->gl_config.driver_loaded) {
   2480            func = _this->GL_GetProcAddress(_this, proc);
   2481        } else {
   2482            SDL_SetError("No GL driver has been loaded");
   2483        }
   2484    } else {
   2485        SDL_SetError("No dynamic GL support in video driver");
   2486    }
   2487    return func;
   2488}
   2489
   2490void
   2491SDL_GL_UnloadLibrary(void)
   2492{
   2493    if (!_this) {
   2494        SDL_UninitializedVideo();
   2495        return;
   2496    }
   2497    if (_this->gl_config.driver_loaded > 0) {
   2498        if (--_this->gl_config.driver_loaded > 0) {
   2499            return;
   2500        }
   2501        if (_this->GL_UnloadLibrary) {
   2502            _this->GL_UnloadLibrary(_this);
   2503        }
   2504    }
   2505}
   2506
   2507static SDL_INLINE SDL_bool
   2508isAtLeastGL3(const char *verstr)
   2509{
   2510    return (verstr && (SDL_atoi(verstr) >= 3));
   2511}
   2512
   2513SDL_bool
   2514SDL_GL_ExtensionSupported(const char *extension)
   2515{
   2516#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   2517    const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
   2518    const char *extensions;
   2519    const char *start;
   2520    const char *where, *terminator;
   2521
   2522    /* Extension names should not have spaces. */
   2523    where = SDL_strchr(extension, ' ');
   2524    if (where || *extension == '\0') {
   2525        return SDL_FALSE;
   2526    }
   2527    /* See if there's an environment variable override */
   2528    start = SDL_getenv(extension);
   2529    if (start && *start == '0') {
   2530        return SDL_FALSE;
   2531    }
   2532
   2533    /* Lookup the available extensions */
   2534
   2535    glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
   2536    if (!glGetStringFunc) {
   2537        return SDL_FALSE;
   2538    }
   2539
   2540    if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
   2541        const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
   2542        void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
   2543        GLint num_exts = 0;
   2544        GLint i;
   2545
   2546        glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
   2547        glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
   2548        if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
   2549            return SDL_FALSE;
   2550        }
   2551
   2552        #ifndef GL_NUM_EXTENSIONS
   2553        #define GL_NUM_EXTENSIONS 0x821D
   2554        #endif
   2555        glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
   2556        for (i = 0; i < num_exts; i++) {
   2557            const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
   2558            if (SDL_strcmp(thisext, extension) == 0) {
   2559                return SDL_TRUE;
   2560            }
   2561        }
   2562
   2563        return SDL_FALSE;
   2564    }
   2565
   2566    /* Try the old way with glGetString(GL_EXTENSIONS) ... */
   2567
   2568    extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
   2569    if (!extensions) {
   2570        return SDL_FALSE;
   2571    }
   2572    /*
   2573     * It takes a bit of care to be fool-proof about parsing the OpenGL
   2574     * extensions string. Don't be fooled by sub-strings, etc.
   2575     */
   2576
   2577    start = extensions;
   2578
   2579    for (;;) {
   2580        where = SDL_strstr(start, extension);
   2581        if (!where)
   2582            break;
   2583
   2584        terminator = where + SDL_strlen(extension);
   2585        if (where == start || *(where - 1) == ' ')
   2586            if (*terminator == ' ' || *terminator == '\0')
   2587                return SDL_TRUE;
   2588
   2589        start = terminator;
   2590    }
   2591    return SDL_FALSE;
   2592#else
   2593    return SDL_FALSE;
   2594#endif
   2595}
   2596
   2597void
   2598SDL_GL_ResetAttributes()
   2599{
   2600    if (!_this) {
   2601        return;
   2602    }
   2603
   2604    _this->gl_config.red_size = 3;
   2605    _this->gl_config.green_size = 3;
   2606    _this->gl_config.blue_size = 2;
   2607    _this->gl_config.alpha_size = 0;
   2608    _this->gl_config.buffer_size = 0;
   2609    _this->gl_config.depth_size = 16;
   2610    _this->gl_config.stencil_size = 0;
   2611    _this->gl_config.double_buffer = 1;
   2612    _this->gl_config.accum_red_size = 0;
   2613    _this->gl_config.accum_green_size = 0;
   2614    _this->gl_config.accum_blue_size = 0;
   2615    _this->gl_config.accum_alpha_size = 0;
   2616    _this->gl_config.stereo = 0;
   2617    _this->gl_config.multisamplebuffers = 0;
   2618    _this->gl_config.multisamplesamples = 0;
   2619    _this->gl_config.retained_backing = 1;
   2620    _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
   2621    _this->gl_config.profile_mask = 0;
   2622#if SDL_VIDEO_OPENGL
   2623    _this->gl_config.major_version = 2;
   2624    _this->gl_config.minor_version = 1;
   2625#elif SDL_VIDEO_OPENGL_ES2
   2626    _this->gl_config.major_version = 2;
   2627    _this->gl_config.minor_version = 0;
   2628    _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
   2629#elif SDL_VIDEO_OPENGL_ES
   2630    _this->gl_config.major_version = 1;
   2631    _this->gl_config.minor_version = 1;
   2632    _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
   2633#endif
   2634    _this->gl_config.flags = 0;
   2635    _this->gl_config.framebuffer_srgb_capable = 0;
   2636
   2637    _this->gl_config.share_with_current_context = 0;
   2638}
   2639
   2640int
   2641SDL_GL_SetAttribute(SDL_GLattr attr, int value)
   2642{
   2643#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   2644    int retval;
   2645
   2646    if (!_this) {
   2647        return SDL_UninitializedVideo();
   2648    }
   2649    retval = 0;
   2650    switch (attr) {
   2651    case SDL_GL_RED_SIZE:
   2652        _this->gl_config.red_size = value;
   2653        break;
   2654    case SDL_GL_GREEN_SIZE:
   2655        _this->gl_config.green_size = value;
   2656        break;
   2657    case SDL_GL_BLUE_SIZE:
   2658        _this->gl_config.blue_size = value;
   2659        break;
   2660    case SDL_GL_ALPHA_SIZE:
   2661        _this->gl_config.alpha_size = value;
   2662        break;
   2663    case SDL_GL_DOUBLEBUFFER:
   2664        _this->gl_config.double_buffer = value;
   2665        break;
   2666    case SDL_GL_BUFFER_SIZE:
   2667        _this->gl_config.buffer_size = value;
   2668        break;
   2669    case SDL_GL_DEPTH_SIZE:
   2670        _this->gl_config.depth_size = value;
   2671        break;
   2672    case SDL_GL_STENCIL_SIZE:
   2673        _this->gl_config.stencil_size = value;
   2674        break;
   2675    case SDL_GL_ACCUM_RED_SIZE:
   2676        _this->gl_config.accum_red_size = value;
   2677        break;
   2678    case SDL_GL_ACCUM_GREEN_SIZE:
   2679        _this->gl_config.accum_green_size = value;
   2680        break;
   2681    case SDL_GL_ACCUM_BLUE_SIZE:
   2682        _this->gl_config.accum_blue_size = value;
   2683        break;
   2684    case SDL_GL_ACCUM_ALPHA_SIZE:
   2685        _this->gl_config.accum_alpha_size = value;
   2686        break;
   2687    case SDL_GL_STEREO:
   2688        _this->gl_config.stereo = value;
   2689        break;
   2690    case SDL_GL_MULTISAMPLEBUFFERS:
   2691        _this->gl_config.multisamplebuffers = value;
   2692        break;
   2693    case SDL_GL_MULTISAMPLESAMPLES:
   2694        _this->gl_config.multisamplesamples = value;
   2695        break;
   2696    case SDL_GL_ACCELERATED_VISUAL:
   2697        _this->gl_config.accelerated = value;
   2698        break;
   2699    case SDL_GL_RETAINED_BACKING:
   2700        _this->gl_config.retained_backing = value;
   2701        break;
   2702    case SDL_GL_CONTEXT_MAJOR_VERSION:
   2703        _this->gl_config.major_version = value;
   2704        break;
   2705    case SDL_GL_CONTEXT_MINOR_VERSION:
   2706        _this->gl_config.minor_version = value;
   2707        break;
   2708    case SDL_GL_CONTEXT_EGL:
   2709        /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
   2710        if (value != 0) {
   2711            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
   2712        } else {
   2713            SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
   2714        };
   2715        break;
   2716    case SDL_GL_CONTEXT_FLAGS:
   2717        if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
   2718                      SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
   2719                      SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
   2720                      SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
   2721            retval = SDL_SetError("Unknown OpenGL context flag %d", value);
   2722            break;
   2723        }
   2724        _this->gl_config.flags = value;
   2725        break;
   2726    case SDL_GL_CONTEXT_PROFILE_MASK:
   2727        if (value != 0 &&
   2728            value != SDL_GL_CONTEXT_PROFILE_CORE &&
   2729            value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
   2730            value != SDL_GL_CONTEXT_PROFILE_ES) {
   2731            retval = SDL_SetError("Unknown OpenGL context profile %d", value);
   2732            break;
   2733        }
   2734        _this->gl_config.profile_mask = value;
   2735        break;
   2736    case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
   2737        _this->gl_config.share_with_current_context = value;
   2738        break;
   2739    case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
   2740        _this->gl_config.framebuffer_srgb_capable = value;
   2741        break;
   2742    default:
   2743        retval = SDL_SetError("Unknown OpenGL attribute");
   2744        break;
   2745    }
   2746    return retval;
   2747#else
   2748    return SDL_Unsupported();
   2749#endif /* SDL_VIDEO_OPENGL */
   2750}
   2751
   2752int
   2753SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
   2754{
   2755#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   2756    void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
   2757    GLenum(APIENTRY * glGetErrorFunc) (void);
   2758    GLenum attrib = 0;
   2759    GLenum error = 0;
   2760
   2761    glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
   2762    if (!glGetIntegervFunc) {
   2763        return -1;
   2764    }
   2765
   2766    glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
   2767    if (!glGetErrorFunc) {
   2768        return -1;
   2769    }
   2770
   2771    /* Clear value in any case */
   2772    *value = 0;
   2773
   2774    switch (attr) {
   2775    case SDL_GL_RED_SIZE:
   2776        attrib = GL_RED_BITS;
   2777        break;
   2778    case SDL_GL_BLUE_SIZE:
   2779        attrib = GL_BLUE_BITS;
   2780        break;
   2781    case SDL_GL_GREEN_SIZE:
   2782        attrib = GL_GREEN_BITS;
   2783        break;
   2784    case SDL_GL_ALPHA_SIZE:
   2785        attrib = GL_ALPHA_BITS;
   2786        break;
   2787    case SDL_GL_DOUBLEBUFFER:
   2788#if SDL_VIDEO_OPENGL
   2789        attrib = GL_DOUBLEBUFFER;
   2790        break;
   2791#else
   2792        /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
   2793        /* parameter which switches double buffer to single buffer. OpenGL ES */
   2794        /* SDL driver must set proper value after initialization              */
   2795        *value = _this->gl_config.double_buffer;
   2796        return 0;
   2797#endif
   2798    case SDL_GL_DEPTH_SIZE:
   2799        attrib = GL_DEPTH_BITS;
   2800        break;
   2801    case SDL_GL_STENCIL_SIZE:
   2802        attrib = GL_STENCIL_BITS;
   2803        break;
   2804#if SDL_VIDEO_OPENGL
   2805    case SDL_GL_ACCUM_RED_SIZE:
   2806        attrib = GL_ACCUM_RED_BITS;
   2807        break;
   2808    case SDL_GL_ACCUM_GREEN_SIZE:
   2809        attrib = GL_ACCUM_GREEN_BITS;
   2810        break;
   2811    case SDL_GL_ACCUM_BLUE_SIZE:
   2812        attrib = GL_ACCUM_BLUE_BITS;
   2813        break;
   2814    case SDL_GL_ACCUM_ALPHA_SIZE:
   2815        attrib = GL_ACCUM_ALPHA_BITS;
   2816        break;
   2817    case SDL_GL_STEREO:
   2818        attrib = GL_STEREO;
   2819        break;
   2820#else
   2821    case SDL_GL_ACCUM_RED_SIZE:
   2822    case SDL_GL_ACCUM_GREEN_SIZE:
   2823    case SDL_GL_ACCUM_BLUE_SIZE:
   2824    case SDL_GL_ACCUM_ALPHA_SIZE:
   2825    case SDL_GL_STEREO:
   2826        /* none of these are supported in OpenGL ES */
   2827        *value = 0;
   2828        return 0;
   2829#endif
   2830    case SDL_GL_MULTISAMPLEBUFFERS:
   2831#if SDL_VIDEO_OPENGL
   2832        attrib = GL_SAMPLE_BUFFERS_ARB;
   2833#else
   2834        attrib = GL_SAMPLE_BUFFERS;
   2835#endif
   2836        break;
   2837    case SDL_GL_MULTISAMPLESAMPLES:
   2838#if SDL_VIDEO_OPENGL
   2839        attrib = GL_SAMPLES_ARB;
   2840#else
   2841        attrib = GL_SAMPLES;
   2842#endif
   2843        break;
   2844    case SDL_GL_BUFFER_SIZE:
   2845        {
   2846            GLint bits = 0;
   2847            GLint component;
   2848
   2849            /*
   2850             * there doesn't seem to be a single flag in OpenGL
   2851             * for this!
   2852             */
   2853            glGetIntegervFunc(GL_RED_BITS, &component);
   2854            bits += component;
   2855            glGetIntegervFunc(GL_GREEN_BITS, &component);
   2856            bits += component;
   2857            glGetIntegervFunc(GL_BLUE_BITS, &component);
   2858            bits += component;
   2859            glGetIntegervFunc(GL_ALPHA_BITS, &component);
   2860            bits += component;
   2861
   2862            *value = bits;
   2863            return 0;
   2864        }
   2865    case SDL_GL_ACCELERATED_VISUAL:
   2866        {
   2867            /* FIXME: How do we get this information? */
   2868            *value = (_this->gl_config.accelerated != 0);
   2869            return 0;
   2870        }
   2871    case SDL_GL_RETAINED_BACKING:
   2872        {
   2873            *value = _this->gl_config.retained_backing;
   2874            return 0;
   2875        }
   2876    case SDL_GL_CONTEXT_MAJOR_VERSION:
   2877        {
   2878            *value = _this->gl_config.major_version;
   2879            return 0;
   2880        }
   2881    case SDL_GL_CONTEXT_MINOR_VERSION:
   2882        {
   2883            *value = _this->gl_config.minor_version;
   2884            return 0;
   2885        }
   2886    case SDL_GL_CONTEXT_EGL:
   2887        /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
   2888        {
   2889            if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   2890                *value = 1;
   2891            }
   2892            else {
   2893                *value = 0;
   2894            }
   2895            return 0;
   2896        }
   2897    case SDL_GL_CONTEXT_FLAGS:
   2898        {
   2899            *value = _this->gl_config.flags;
   2900            return 0;
   2901        }
   2902    case SDL_GL_CONTEXT_PROFILE_MASK:
   2903        {
   2904            *value = _this->gl_config.profile_mask;
   2905            return 0;
   2906        }
   2907    case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
   2908        {
   2909            *value = _this->gl_config.share_with_current_context;
   2910            return 0;
   2911        }
   2912    case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
   2913        {
   2914            *value = _this->gl_config.framebuffer_srgb_capable;
   2915            return 0;
   2916        }
   2917    default:
   2918        return SDL_SetError("Unknown OpenGL attribute");
   2919    }
   2920
   2921    glGetIntegervFunc(attrib, (GLint *) value);
   2922    error = glGetErrorFunc();
   2923    if (error != GL_NO_ERROR) {
   2924        if (error == GL_INVALID_ENUM) {
   2925            return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
   2926        } else if (error == GL_INVALID_VALUE) {
   2927            return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
   2928        }
   2929        return SDL_SetError("OpenGL error: %08X", error);
   2930    }
   2931    return 0;
   2932#else
   2933    return SDL_Unsupported();
   2934#endif /* SDL_VIDEO_OPENGL */
   2935}
   2936
   2937SDL_GLContext
   2938SDL_GL_CreateContext(SDL_Window * window)
   2939{
   2940    SDL_GLContext ctx = NULL;
   2941    CHECK_WINDOW_MAGIC(window, NULL);
   2942
   2943    if (!(window->flags & SDL_WINDOW_OPENGL)) {
   2944        SDL_SetError("The specified window isn't an OpenGL window");
   2945        return NULL;
   2946    }
   2947
   2948    ctx = _this->GL_CreateContext(_this, window);
   2949
   2950    /* Creating a context is assumed to make it current in the SDL driver. */
   2951    if (ctx) {
   2952        _this->current_glwin = window;
   2953        _this->current_glctx = ctx;
   2954        SDL_TLSSet(_this->current_glwin_tls, window, NULL);
   2955        SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
   2956    }
   2957    return ctx;
   2958}
   2959
   2960int
   2961SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
   2962{
   2963    int retval;
   2964
   2965    if (window == SDL_GL_GetCurrentWindow() &&
   2966        ctx == SDL_GL_GetCurrentContext()) {
   2967        /* We're already current. */
   2968        return 0;
   2969    }
   2970
   2971    if (!ctx) {
   2972        window = NULL;
   2973    } else {
   2974        CHECK_WINDOW_MAGIC(window, -1);
   2975
   2976        if (!(window->flags & SDL_WINDOW_OPENGL)) {
   2977            return SDL_SetError("The specified window isn't an OpenGL window");
   2978        }
   2979    }
   2980
   2981    retval = _this->GL_MakeCurrent(_this, window, ctx);
   2982    if (retval == 0) {
   2983        _this->current_glwin = window;
   2984        _this->current_glctx = ctx;
   2985        SDL_TLSSet(_this->current_glwin_tls, window, NULL);
   2986        SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
   2987    }
   2988    return retval;
   2989}
   2990
   2991SDL_Window *
   2992SDL_GL_GetCurrentWindow(void)
   2993{
   2994    if (!_this) {
   2995        SDL_UninitializedVideo();
   2996        return NULL;
   2997    }
   2998    return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
   2999}
   3000
   3001SDL_GLContext
   3002SDL_GL_GetCurrentContext(void)
   3003{
   3004    if (!_this) {
   3005        SDL_UninitializedVideo();
   3006        return NULL;
   3007    }
   3008    return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
   3009}
   3010
   3011void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
   3012{
   3013    CHECK_WINDOW_MAGIC(window,);
   3014
   3015    if (_this->GL_GetDrawableSize) {
   3016        _this->GL_GetDrawableSize(_this, window, w, h);
   3017    } else {
   3018        SDL_GetWindowSize(window, w, h);
   3019    }
   3020}
   3021
   3022int
   3023SDL_GL_SetSwapInterval(int interval)
   3024{
   3025    if (!_this) {
   3026        return SDL_UninitializedVideo();
   3027    } else if (SDL_GL_GetCurrentContext() == NULL) {
   3028        return SDL_SetError("No OpenGL context has been made current");
   3029    } else if (_this->GL_SetSwapInterval) {
   3030        return _this->GL_SetSwapInterval(_this, interval);
   3031    } else {
   3032        return SDL_SetError("Setting the swap interval is not supported");
   3033    }
   3034}
   3035
   3036int
   3037SDL_GL_GetSwapInterval(void)
   3038{
   3039    if (!_this) {
   3040        return 0;
   3041    } else if (SDL_GL_GetCurrentContext() == NULL) {
   3042        return 0;
   3043    } else if (_this->GL_GetSwapInterval) {
   3044        return _this->GL_GetSwapInterval(_this);
   3045    } else {
   3046        return 0;
   3047    }
   3048}
   3049
   3050void
   3051SDL_GL_SwapWindow(SDL_Window * window)
   3052{
   3053    CHECK_WINDOW_MAGIC(window,);
   3054
   3055    if (!(window->flags & SDL_WINDOW_OPENGL)) {
   3056        SDL_SetError("The specified window isn't an OpenGL window");
   3057        return;
   3058    }
   3059
   3060    if (SDL_GL_GetCurrentWindow() != window) {
   3061        SDL_SetError("The specified window has not been made current");
   3062        return;
   3063    }
   3064
   3065    _this->GL_SwapWindow(_this, window);
   3066}
   3067
   3068void
   3069SDL_GL_DeleteContext(SDL_GLContext context)
   3070{
   3071    if (!_this || !context) {
   3072        return;
   3073    }
   3074
   3075    if (SDL_GL_GetCurrentContext() == context) {
   3076        SDL_GL_MakeCurrent(NULL, NULL);
   3077    }
   3078
   3079    _this->GL_DeleteContext(_this, context);
   3080}
   3081
   3082#if 0                           /* FIXME */
   3083/*
   3084 * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
   3085 * & 2 for alpha channel.
   3086 */
   3087static void
   3088CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
   3089{
   3090    int x, y;
   3091    Uint32 colorkey;
   3092#define SET_MASKBIT(icon, x, y, mask) \
   3093    mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
   3094
   3095    colorkey = icon->format->colorkey;
   3096    switch (icon->format->BytesPerPixel) {
   3097    case 1:
   3098        {
   3099            Uint8 *pixels;
   3100            for (y = 0; y < icon->h; ++y) {
   3101                pixels = (Uint8 *) icon->pixels + y * icon->pitch;
   3102                for (x = 0; x < icon->w; ++x) {
   3103                    if (*pixels++ == colorkey) {
   3104                        SET_MASKBIT(icon, x, y, mask);
   3105                    }
   3106                }
   3107            }
   3108        }
   3109        break;
   3110
   3111    case 2:
   3112        {
   3113            Uint16 *pixels;
   3114            for (y = 0; y < icon->h; ++y) {
   3115                pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
   3116                for (x = 0; x < icon->w; ++x) {
   3117                    if ((flags & 1) && *pixels == colorkey) {
   3118                        SET_MASKBIT(icon, x, y, mask);
   3119                    } else if ((flags & 2)
   3120                               && (*pixels & icon->format->Amask) == 0) {
   3121                        SET_MASKBIT(icon, x, y, mask);
   3122                    }
   3123                    pixels++;
   3124                }
   3125            }
   3126        }
   3127        break;
   3128
   3129    case 4:
   3130        {
   3131            Uint32 *pixels;
   3132            for (y = 0; y < icon->h; ++y) {
   3133                pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
   3134                for (x = 0; x < icon->w; ++x) {
   3135                    if ((flags & 1) && *pixels == colorkey) {
   3136                        SET_MASKBIT(icon, x, y, mask);
   3137                    } else if ((flags & 2)
   3138                               && (*pixels & icon->format->Amask) == 0) {
   3139                        SET_MASKBIT(icon, x, y, mask);
   3140                    }
   3141                    pixels++;
   3142                }
   3143            }
   3144        }
   3145        break;
   3146    }
   3147}
   3148
   3149/*
   3150 * Sets the window manager icon for the display window.
   3151 */
   3152void
   3153SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
   3154{
   3155    if (icon && _this->SetIcon) {
   3156        /* Generate a mask if necessary, and create the icon! */
   3157        if (mask == NULL) {
   3158            int mask_len = icon->h * (icon->w + 7) / 8;
   3159            int flags = 0;
   3160            mask = (Uint8 *) SDL_malloc(mask_len);
   3161            if (mask == NULL) {
   3162                return;
   3163            }
   3164            SDL_memset(mask, ~0, mask_len);
   3165            if (icon->flags & SDL_SRCCOLORKEY)
   3166                flags |= 1;
   3167            if (icon->flags & SDL_SRCALPHA)
   3168                flags |= 2;
   3169            if (flags) {
   3170                CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
   3171            }
   3172            _this->SetIcon(_this, icon, mask);
   3173            SDL_free(mask);
   3174        } else {
   3175            _this->SetIcon(_this, icon, mask);
   3176        }
   3177    }
   3178}
   3179#endif
   3180
   3181SDL_bool
   3182SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
   3183{
   3184    CHECK_WINDOW_MAGIC(window, SDL_FALSE);
   3185
   3186    if (!info) {
   3187        SDL_InvalidParamError("info");
   3188        return SDL_FALSE;
   3189    }
   3190    info->subsystem = SDL_SYSWM_UNKNOWN;
   3191
   3192    if (!_this->GetWindowWMInfo) {
   3193        SDL_Unsupported();
   3194        return SDL_FALSE;
   3195    }
   3196    return (_this->GetWindowWMInfo(_this, window, info));
   3197}
   3198
   3199void
   3200SDL_StartTextInput(void)
   3201{
   3202    SDL_Window *window;
   3203
   3204    /* First, enable text events */
   3205    SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
   3206    SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
   3207
   3208    /* Then show the on-screen keyboard, if any */
   3209    window = SDL_GetFocusWindow();
   3210    if (window && _this && _this->ShowScreenKeyboard) {
   3211        _this->ShowScreenKeyboard(_this, window);
   3212    }
   3213
   3214    /* Finally start the text input system */
   3215    if (_this && _this->StartTextInput) {
   3216        _this->StartTextInput(_this);
   3217    }
   3218}
   3219
   3220SDL_bool
   3221SDL_IsTextInputActive(void)
   3222{
   3223    return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
   3224}
   3225
   3226void
   3227SDL_StopTextInput(void)
   3228{
   3229    SDL_Window *window;
   3230
   3231    /* Stop the text input system */
   3232    if (_this && _this->StopTextInput) {
   3233        _this->StopTextInput(_this);
   3234    }
   3235
   3236    /* Hide the on-screen keyboard, if any */
   3237    window = SDL_GetFocusWindow();
   3238    if (window && _this && _this->HideScreenKeyboard) {
   3239        _this->HideScreenKeyboard(_this, window);
   3240    }
   3241
   3242    /* Finally disable text events */
   3243    SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
   3244    SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
   3245}
   3246
   3247void
   3248SDL_SetTextInputRect(SDL_Rect *rect)
   3249{
   3250    if (_this && _this->SetTextInputRect) {
   3251        _this->SetTextInputRect(_this, rect);
   3252    }
   3253}
   3254
   3255SDL_bool
   3256SDL_HasScreenKeyboardSupport(void)
   3257{
   3258    if (_this && _this->HasScreenKeyboardSupport) {
   3259        return _this->HasScreenKeyboardSupport(_this);
   3260    }
   3261    return SDL_FALSE;
   3262}
   3263
   3264SDL_bool
   3265SDL_IsScreenKeyboardShown(SDL_Window *window)
   3266{
   3267    if (window && _this && _this->IsScreenKeyboardShown) {
   3268        return _this->IsScreenKeyboardShown(_this, window);
   3269    }
   3270    return SDL_FALSE;
   3271}
   3272
   3273#if SDL_VIDEO_DRIVER_ANDROID
   3274#include "android/SDL_androidmessagebox.h"
   3275#endif
   3276#if SDL_VIDEO_DRIVER_WINDOWS
   3277#include "windows/SDL_windowsmessagebox.h"
   3278#endif
   3279#if SDL_VIDEO_DRIVER_WINRT
   3280#include "winrt/SDL_winrtmessagebox.h"
   3281#endif
   3282#if SDL_VIDEO_DRIVER_COCOA
   3283#include "cocoa/SDL_cocoamessagebox.h"
   3284#endif
   3285#if SDL_VIDEO_DRIVER_UIKIT
   3286#include "uikit/SDL_uikitmessagebox.h"
   3287#endif
   3288#if SDL_VIDEO_DRIVER_X11
   3289#include "x11/SDL_x11messagebox.h"
   3290#endif
   3291
   3292// This function will be unused if none of the above video drivers are present.
   3293SDL_UNUSED static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
   3294{
   3295    SDL_SysWMinfo info;
   3296    SDL_Window *window = messageboxdata->window;
   3297
   3298    if (!window) {
   3299        return SDL_TRUE;
   3300    }
   3301
   3302    SDL_VERSION(&info.version);
   3303    if (!SDL_GetWindowWMInfo(window, &info)) {
   3304        return SDL_TRUE;
   3305    } else {
   3306        return (info.subsystem == drivertype);
   3307    }
   3308}
   3309
   3310int
   3311SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
   3312{
   3313    int dummybutton;
   3314    int retval = -1;
   3315    SDL_bool relative_mode;
   3316    int show_cursor_prev;
   3317    SDL_bool mouse_captured;
   3318    SDL_Window *current_window;
   3319
   3320    if (!messageboxdata) {
   3321        return SDL_InvalidParamError("messageboxdata");
   3322    }
   3323
   3324    current_window = SDL_GetKeyboardFocus();
   3325    mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
   3326    relative_mode = SDL_GetRelativeMouseMode();
   3327    SDL_CaptureMouse(SDL_FALSE);
   3328    SDL_SetRelativeMouseMode(SDL_FALSE);
   3329    show_cursor_prev = SDL_ShowCursor(1);
   3330
   3331    if (!buttonid) {
   3332        buttonid = &dummybutton;
   3333    }
   3334
   3335    if (_this && _this->ShowMessageBox) {
   3336        retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
   3337    }
   3338
   3339    /* It's completely fine to call this function before video is initialized */
   3340#if SDL_VIDEO_DRIVER_ANDROID
   3341    if (retval == -1 &&
   3342        Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
   3343        retval = 0;
   3344    }
   3345#endif
   3346#if SDL_VIDEO_DRIVER_WINDOWS
   3347    if (retval == -1 &&
   3348        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
   3349        WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
   3350        retval = 0;
   3351    }
   3352#endif
   3353#if SDL_VIDEO_DRIVER_WINRT
   3354    if (retval == -1 &&
   3355        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
   3356        WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
   3357        retval = 0;
   3358    }
   3359#endif
   3360#if SDL_VIDEO_DRIVER_COCOA
   3361    if (retval == -1 &&
   3362        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
   3363        Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
   3364        retval = 0;
   3365    }
   3366#endif
   3367#if SDL_VIDEO_DRIVER_UIKIT
   3368    if (retval == -1 &&
   3369        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
   3370        UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
   3371        retval = 0;
   3372    }
   3373#endif
   3374#if SDL_VIDEO_DRIVER_X11
   3375    if (retval == -1 &&
   3376        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
   3377        X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
   3378        retval = 0;
   3379    }
   3380#endif
   3381    if (retval == -1) {
   3382        SDL_SetError("No message system available");
   3383    }
   3384
   3385    if (current_window) {
   3386        SDL_RaiseWindow(current_window);
   3387        if (mouse_captured) {
   3388            SDL_CaptureMouse(SDL_TRUE);
   3389        }
   3390    }
   3391
   3392    SDL_ShowCursor(show_cursor_prev);
   3393    SDL_SetRelativeMouseMode(relative_mode);
   3394
   3395    return retval;
   3396}
   3397
   3398int
   3399SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
   3400{
   3401    SDL_MessageBoxData data;
   3402    SDL_MessageBoxButtonData button;
   3403
   3404    SDL_zero(data);
   3405    data.flags = flags;
   3406    data.title = title;
   3407    data.message = message;
   3408    data.numbuttons = 1;
   3409    data.buttons = &button;
   3410    data.window = window;
   3411
   3412    SDL_zero(button);
   3413    button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
   3414    button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
   3415    button.text = "OK";
   3416
   3417    return SDL_ShowMessageBox(&data, NULL);
   3418}
   3419
   3420SDL_bool
   3421SDL_ShouldAllowTopmost(void)
   3422{
   3423    const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
   3424    if (hint) {
   3425        if (*hint == '0') {
   3426            return SDL_FALSE;
   3427        } else {
   3428            return SDL_TRUE;
   3429        }
   3430    }
   3431    return SDL_TRUE;
   3432}
   3433
   3434int
   3435SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
   3436{
   3437    CHECK_WINDOW_MAGIC(window, -1);
   3438
   3439    if (!_this->SetWindowHitTest) {
   3440        return SDL_Unsupported();
   3441    } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
   3442        return -1;
   3443    }
   3444
   3445    window->hit_test = callback;
   3446    window->hit_test_data = userdata;
   3447
   3448    return 0;
   3449}
   3450
   3451/* vi: set ts=4 sw=4 expandtab: */