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