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