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