src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 20 May 2019 00:41:18 -0400
changeset 12743 c653e9fa9ca9
parent 12736 d3421eeb57a0
permissions -rw-r--r--
vulkan: Swapped out a free() that should have been an SDL_free().

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