src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 02 Aug 2017 10:22:48 -0700
changeset 11175 cbc6a8a5b701
parent 11171 6f6e8880cd37
child 11183 2b3b51f36654
permissions -rw-r--r--
Fixed bug 3690 - SDL2 KMS/DRM render context support

Manuel

The attached patch adds support for KMS/DRM context graphics.

It builds with no problem on X86_64 GNU/Linux systems, provided the needed libraries are present, and on ARM GNU/Linux systems that have KMS/DRM support and a GLES2 implementation.
Tested on Raspberry Pi: KMS/DRM is what the Raspberry Pi will use as default in the near future, once the propietary DispmanX API by Broadcom is overtaken by open graphics stack, it's possible to boot current Raspbian system in KMS mode by adding "dtoverlay=vc4-kms-v3d" to config.txt on Raspbian's boot partition.
X86 systems use KMS right away in every current GNU/Linux system.

Simple build instructions:

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