src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 02 Aug 2018 16:03:47 -0400
changeset 12070 1d65571b57dd
parent 12017 d8a165136edf
child 12143 673ec0369266
permissions -rw-r--r--
Some drag'and'drop improvements.

First: disable d'n'd events by default; most apps don't need these at all, and
if an app doesn't explicitly handle these, each drop on the window will cause
a memory leak if the events are enabled. This follows the guidelines we have
for SDL_TEXTINPUT events already.

Second: when events are enabled or disabled, signal the video layer, as it
might be able to inform the OS, causing UI changes or optimizations (for
example, dropping a file icon on a Cocoa app that isn't accepting drops will
cause macOS to show a rejection animation instead of the drop operation just
vanishing into the ether, X11 might show a different cursor when dragging
onto an accepting window, etc).

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