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