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