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