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