src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 05 Jun 2018 12:46:09 -0700
changeset 12006 1b7ed3438a7f
parent 11954 bc2aba33ae1f
child 12017 d8a165136edf
permissions -rw-r--r--
Fix creating a minimized window in SDL to not cause focus to be stolen (because ShowWindow( hwnd, SW_MINIMIZE ) would be called after creation, thus changing focus to the prior window based on some per-app list in windows, rather than the window being created with WS_MINIMIZED to start with).

This means we have to consider SDL_WINDOW_MINIMIZED a window creation flag, but on non-windows platforms we just remove it and let the normal FinishWindowCreation re-apply and do the minimize as I have no idea what is right on them or if anything should change.

CR: Phil
     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                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1293                                         fullscreen_mode.w, fullscreen_mode.h);
  1294                 } else {
  1295                     SDL_OnWindowResized(other);
  1296                 }
  1297 
  1298                 SDL_RestoreMousePosition(other);
  1299 
  1300                 window->last_fullscreen_flags = window->flags;
  1301                 return 0;
  1302             }
  1303         }
  1304     }
  1305 
  1306     /* Nope, restore the desktop mode */
  1307     SDL_SetDisplayModeForDisplay(display, NULL);
  1308 
  1309     if (_this->SetWindowFullscreen) {
  1310         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1311     }
  1312     display->fullscreen_window = NULL;
  1313 
  1314     /* Generate a mode change event here */
  1315     SDL_OnWindowResized(window);
  1316 
  1317     /* Restore the cursor position */
  1318     SDL_RestoreMousePosition(window);
  1319 
  1320     window->last_fullscreen_flags = window->flags;
  1321     return 0;
  1322 }
  1323 
  1324 #define CREATE_FLAGS \
  1325     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED)
  1326 
  1327 static void
  1328 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1329 {
  1330     if (flags & SDL_WINDOW_MAXIMIZED) {
  1331         SDL_MaximizeWindow(window);
  1332     }
  1333     if (flags & SDL_WINDOW_MINIMIZED) {
  1334         SDL_MinimizeWindow(window);
  1335     }
  1336     if (flags & SDL_WINDOW_FULLSCREEN) {
  1337         SDL_SetWindowFullscreen(window, flags);
  1338     }
  1339     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1340         SDL_SetWindowGrab(window, SDL_TRUE);
  1341     }
  1342     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1343         SDL_ShowWindow(window);
  1344     }
  1345 }
  1346 
  1347 SDL_Window *
  1348 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1349 {
  1350     SDL_Window *window;
  1351 
  1352     if (!_this) {
  1353         /* Initialize the video system if needed */
  1354         if (SDL_VideoInit(NULL) < 0) {
  1355             return NULL;
  1356         }
  1357     }
  1358 
  1359     if ((((flags & SDL_WINDOW_UTILITY) != 0) + ((flags & SDL_WINDOW_TOOLTIP) != 0) + ((flags & SDL_WINDOW_POPUP_MENU) != 0)) > 1) {
  1360         SDL_SetError("Conflicting window flags specified");
  1361         return NULL;
  1362     }
  1363 
  1364     /* Some platforms can't create zero-sized windows */
  1365     if (w < 1) {
  1366         w = 1;
  1367     }
  1368     if (h < 1) {
  1369         h = 1;
  1370     }
  1371 
  1372     /* Some platforms blow up if the windows are too large. Raise it later? */
  1373     if ((w > 16384) || (h > 16384)) {
  1374         SDL_SetError("Window is too large.");
  1375         return NULL;
  1376     }
  1377 
  1378     /* Some platforms have OpenGL enabled by default */
  1379 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
  1380     if (!_this->is_dummy && !(flags & SDL_WINDOW_VULKAN)) {
  1381         flags |= SDL_WINDOW_OPENGL;
  1382     }
  1383 #endif
  1384     if (flags & SDL_WINDOW_OPENGL) {
  1385         if (!_this->GL_CreateContext) {
  1386             SDL_SetError("OpenGL support is either not configured in SDL "
  1387                          "or not available in current SDL video driver "
  1388                          "(%s) or platform", _this->name);
  1389             return NULL;
  1390         }
  1391         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1392             return NULL;
  1393         }
  1394     }
  1395 
  1396     if (flags & SDL_WINDOW_VULKAN) {
  1397         if (!_this->Vulkan_CreateSurface) {
  1398             SDL_SetError("Vulkan support is either not configured in SDL "
  1399                          "or not available in current SDL video driver "
  1400                          "(%s) or platform", _this->name);
  1401             return NULL;
  1402         }
  1403         if (flags & SDL_WINDOW_OPENGL) {
  1404             SDL_SetError("Vulkan and OpenGL not supported on same window");
  1405             return NULL;
  1406         }
  1407         if (SDL_Vulkan_LoadLibrary(NULL) < 0) {
  1408             return NULL;
  1409         }
  1410     }
  1411 
  1412     /* Unless the user has specified the high-DPI disabling hint, respect the
  1413      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1414      */
  1415     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1416         if (SDL_GetHintBoolean(SDL_HINT_VIDEO_HIGHDPI_DISABLED, SDL_FALSE)) {
  1417             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1418         }
  1419     }
  1420 
  1421     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1422     if (!window) {
  1423         SDL_OutOfMemory();
  1424         return NULL;
  1425     }
  1426     window->magic = &_this->window_magic;
  1427     window->id = _this->next_object_id++;
  1428     window->x = x;
  1429     window->y = y;
  1430     window->w = w;
  1431     window->h = h;
  1432     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1433         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1434         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1435         int displayIndex;
  1436         SDL_Rect bounds;
  1437 
  1438         displayIndex = SDL_GetIndexOfDisplay(display);
  1439         SDL_GetDisplayBounds(displayIndex, &bounds);
  1440         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1441             window->x = bounds.x + (bounds.w - w) / 2;
  1442         }
  1443         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1444             window->y = bounds.y + (bounds.h - h) / 2;
  1445         }
  1446     }
  1447     window->windowed.x = window->x;
  1448     window->windowed.y = window->y;
  1449     window->windowed.w = window->w;
  1450     window->windowed.h = window->h;
  1451 
  1452     if (flags & SDL_WINDOW_FULLSCREEN) {
  1453         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1454         int displayIndex;
  1455         SDL_Rect bounds;
  1456 
  1457         displayIndex = SDL_GetIndexOfDisplay(display);
  1458         SDL_GetDisplayBounds(displayIndex, &bounds);
  1459 
  1460         window->x = bounds.x;
  1461         window->y = bounds.y;
  1462         window->w = bounds.w;
  1463         window->h = bounds.h;
  1464     }
  1465 
  1466     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1467     window->last_fullscreen_flags = window->flags;
  1468     window->opacity = 1.0f;
  1469     window->brightness = 1.0f;
  1470     window->next = _this->windows;
  1471     window->is_destroying = SDL_FALSE;
  1472 
  1473     if (_this->windows) {
  1474         _this->windows->prev = window;
  1475     }
  1476     _this->windows = window;
  1477 
  1478     if (_this->CreateSDLWindow && _this->CreateSDLWindow(_this, window) < 0) {
  1479         SDL_DestroyWindow(window);
  1480         return NULL;
  1481     }
  1482 
  1483 	// Clear minimized if not on windows, only windows handles it at create rather than FinishWindowCreation,
  1484 	// but it's important or window focus will get broken on windows!
  1485 #if !defined(__WIN32__)
  1486 	if ( window->flags & SDL_WINDOW_MINIMIZED )
  1487 		window->flags &= ~SDL_WINDOW_MINIMIZED;
  1488 #endif
  1489 
  1490 #if __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
  1491     /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
  1492        or not.  The user can choose this, via OS-provided UI, but this can't
  1493        be set programmatically.
  1494 
  1495        Just look at what SDL's WinRT video backend code detected with regards
  1496        to fullscreen (being active, or not), and figure out a return/error code
  1497        from that.
  1498     */
  1499     flags = window->flags;
  1500 #endif
  1501 
  1502     if (title) {
  1503         SDL_SetWindowTitle(window, title);
  1504     }
  1505     SDL_FinishWindowCreation(window, flags);
  1506 
  1507     /* If the window was created fullscreen, make sure the mode code matches */
  1508     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1509 
  1510     return window;
  1511 }
  1512 
  1513 SDL_Window *
  1514 SDL_CreateWindowFrom(const void *data)
  1515 {
  1516     SDL_Window *window;
  1517 
  1518     if (!_this) {
  1519         SDL_UninitializedVideo();
  1520         return NULL;
  1521     }
  1522     if (!_this->CreateSDLWindowFrom) {
  1523         SDL_Unsupported();
  1524         return NULL;
  1525     }
  1526     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1527     if (!window) {
  1528         SDL_OutOfMemory();
  1529         return NULL;
  1530     }
  1531     window->magic = &_this->window_magic;
  1532     window->id = _this->next_object_id++;
  1533     window->flags = SDL_WINDOW_FOREIGN;
  1534     window->last_fullscreen_flags = window->flags;
  1535     window->is_destroying = SDL_FALSE;
  1536     window->opacity = 1.0f;
  1537     window->brightness = 1.0f;
  1538     window->next = _this->windows;
  1539     if (_this->windows) {
  1540         _this->windows->prev = window;
  1541     }
  1542     _this->windows = window;
  1543 
  1544     if (_this->CreateSDLWindowFrom(_this, window, data) < 0) {
  1545         SDL_DestroyWindow(window);
  1546         return NULL;
  1547     }
  1548     return window;
  1549 }
  1550 
  1551 int
  1552 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1553 {
  1554     SDL_bool loaded_opengl = SDL_FALSE;
  1555 
  1556     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1557         return SDL_SetError("OpenGL support is either not configured in SDL "
  1558                             "or not available in current SDL video driver "
  1559                             "(%s) or platform", _this->name);
  1560     }
  1561 
  1562     if (window->flags & SDL_WINDOW_FOREIGN) {
  1563         /* Can't destroy and re-create foreign windows, hrm */
  1564         flags |= SDL_WINDOW_FOREIGN;
  1565     } else {
  1566         flags &= ~SDL_WINDOW_FOREIGN;
  1567     }
  1568 
  1569     /* Restore video mode, etc. */
  1570     SDL_HideWindow(window);
  1571 
  1572     /* Tear down the old native window */
  1573     if (window->surface) {
  1574         window->surface->flags &= ~SDL_DONTFREE;
  1575         SDL_FreeSurface(window->surface);
  1576         window->surface = NULL;
  1577     }
  1578     if (_this->DestroyWindowFramebuffer) {
  1579         _this->DestroyWindowFramebuffer(_this, window);
  1580     }
  1581     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1582         _this->DestroyWindow(_this, window);
  1583     }
  1584 
  1585     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1586         if (flags & SDL_WINDOW_OPENGL) {
  1587             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1588                 return -1;
  1589             }
  1590             loaded_opengl = SDL_TRUE;
  1591         } else {
  1592             SDL_GL_UnloadLibrary();
  1593         }
  1594     }
  1595 
  1596     if ((window->flags & SDL_WINDOW_VULKAN) != (flags & SDL_WINDOW_VULKAN)) {
  1597         SDL_SetError("Can't change SDL_WINDOW_VULKAN window flag");
  1598         return -1;
  1599     }
  1600 
  1601     if ((window->flags & SDL_WINDOW_VULKAN) && (flags & SDL_WINDOW_OPENGL)) {
  1602         SDL_SetError("Vulkan and OpenGL not supported on same window");
  1603         return -1;
  1604     }
  1605 
  1606     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1607     window->last_fullscreen_flags = window->flags;
  1608     window->is_destroying = SDL_FALSE;
  1609 
  1610     if (_this->CreateSDLWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1611         if (_this->CreateSDLWindow(_this, window) < 0) {
  1612             if (loaded_opengl) {
  1613                 SDL_GL_UnloadLibrary();
  1614                 window->flags &= ~SDL_WINDOW_OPENGL;
  1615             }
  1616             return -1;
  1617         }
  1618     }
  1619 
  1620     if (flags & SDL_WINDOW_FOREIGN) {
  1621         window->flags |= SDL_WINDOW_FOREIGN;
  1622     }
  1623 
  1624     if (_this->SetWindowTitle && window->title) {
  1625         _this->SetWindowTitle(_this, window);
  1626     }
  1627 
  1628     if (_this->SetWindowIcon && window->icon) {
  1629         _this->SetWindowIcon(_this, window, window->icon);
  1630     }
  1631 
  1632     if (window->hit_test) {
  1633         _this->SetWindowHitTest(window, SDL_TRUE);
  1634     }
  1635 
  1636     SDL_FinishWindowCreation(window, flags);
  1637 
  1638     return 0;
  1639 }
  1640 
  1641 SDL_bool
  1642 SDL_HasWindows(void)
  1643 {
  1644     return (_this && _this->windows != NULL);
  1645 }
  1646 
  1647 Uint32
  1648 SDL_GetWindowID(SDL_Window * window)
  1649 {
  1650     CHECK_WINDOW_MAGIC(window, 0);
  1651 
  1652     return window->id;
  1653 }
  1654 
  1655 SDL_Window *
  1656 SDL_GetWindowFromID(Uint32 id)
  1657 {
  1658     SDL_Window *window;
  1659 
  1660     if (!_this) {
  1661         return NULL;
  1662     }
  1663     for (window = _this->windows; window; window = window->next) {
  1664         if (window->id == id) {
  1665             return window;
  1666         }
  1667     }
  1668     return NULL;
  1669 }
  1670 
  1671 Uint32
  1672 SDL_GetWindowFlags(SDL_Window * window)
  1673 {
  1674     CHECK_WINDOW_MAGIC(window, 0);
  1675 
  1676     return window->flags;
  1677 }
  1678 
  1679 void
  1680 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1681 {
  1682     CHECK_WINDOW_MAGIC(window,);
  1683 
  1684     if (title == window->title) {
  1685         return;
  1686     }
  1687     SDL_free(window->title);
  1688 
  1689     window->title = SDL_strdup(title ? title : "");
  1690 
  1691     if (_this->SetWindowTitle) {
  1692         _this->SetWindowTitle(_this, window);
  1693     }
  1694 }
  1695 
  1696 const char *
  1697 SDL_GetWindowTitle(SDL_Window * window)
  1698 {
  1699     CHECK_WINDOW_MAGIC(window, "");
  1700 
  1701     return window->title ? window->title : "";
  1702 }
  1703 
  1704 void
  1705 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1706 {
  1707     CHECK_WINDOW_MAGIC(window,);
  1708 
  1709     if (!icon) {
  1710         return;
  1711     }
  1712 
  1713     SDL_FreeSurface(window->icon);
  1714 
  1715     /* Convert the icon into ARGB8888 */
  1716     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1717     if (!window->icon) {
  1718         return;
  1719     }
  1720 
  1721     if (_this->SetWindowIcon) {
  1722         _this->SetWindowIcon(_this, window, window->icon);
  1723     }
  1724 }
  1725 
  1726 void*
  1727 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1728 {
  1729     SDL_WindowUserData *prev, *data;
  1730 
  1731     CHECK_WINDOW_MAGIC(window, NULL);
  1732 
  1733     /* Input validation */
  1734     if (name == NULL || name[0] == '\0') {
  1735       SDL_InvalidParamError("name");
  1736       return NULL;
  1737     }
  1738 
  1739     /* See if the named data already exists */
  1740     prev = NULL;
  1741     for (data = window->data; data; prev = data, data = data->next) {
  1742         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1743             void *last_value = data->data;
  1744 
  1745             if (userdata) {
  1746                 /* Set the new value */
  1747                 data->data = userdata;
  1748             } else {
  1749                 /* Delete this value */
  1750                 if (prev) {
  1751                     prev->next = data->next;
  1752                 } else {
  1753                     window->data = data->next;
  1754                 }
  1755                 SDL_free(data->name);
  1756                 SDL_free(data);
  1757             }
  1758             return last_value;
  1759         }
  1760     }
  1761 
  1762     /* Add new data to the window */
  1763     if (userdata) {
  1764         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1765         data->name = SDL_strdup(name);
  1766         data->data = userdata;
  1767         data->next = window->data;
  1768         window->data = data;
  1769     }
  1770     return NULL;
  1771 }
  1772 
  1773 void *
  1774 SDL_GetWindowData(SDL_Window * window, const char *name)
  1775 {
  1776     SDL_WindowUserData *data;
  1777 
  1778     CHECK_WINDOW_MAGIC(window, NULL);
  1779 
  1780     /* Input validation */
  1781     if (name == NULL || name[0] == '\0') {
  1782       SDL_InvalidParamError("name");
  1783       return NULL;
  1784     }
  1785 
  1786     for (data = window->data; data; data = data->next) {
  1787         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1788             return data->data;
  1789         }
  1790     }
  1791     return NULL;
  1792 }
  1793 
  1794 void
  1795 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1796 {
  1797     CHECK_WINDOW_MAGIC(window,);
  1798 
  1799     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1800         int displayIndex = (x & 0xFFFF);
  1801         SDL_Rect bounds;
  1802         if (displayIndex >= _this->num_displays) {
  1803             displayIndex = 0;
  1804         }
  1805 
  1806         SDL_zero(bounds);
  1807 
  1808         SDL_GetDisplayBounds(displayIndex, &bounds);
  1809         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1810             x = bounds.x + (bounds.w - window->w) / 2;
  1811         }
  1812         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1813             y = bounds.y + (bounds.h - window->h) / 2;
  1814         }
  1815     }
  1816 
  1817     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1818         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1819             window->windowed.x = x;
  1820         }
  1821         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1822             window->windowed.y = y;
  1823         }
  1824     } else {
  1825         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1826             window->x = x;
  1827         }
  1828         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1829             window->y = y;
  1830         }
  1831 
  1832         if (_this->SetWindowPosition) {
  1833             _this->SetWindowPosition(_this, window);
  1834         }
  1835         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1836     }
  1837 }
  1838 
  1839 void
  1840 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1841 {
  1842     CHECK_WINDOW_MAGIC(window,);
  1843 
  1844     /* Fullscreen windows are always at their display's origin */
  1845     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1846         int displayIndex;
  1847         
  1848         if (x) {
  1849             *x = 0;
  1850         }
  1851         if (y) {
  1852             *y = 0;
  1853         }
  1854 
  1855         /* Find the window's monitor and update to the
  1856            monitor offset. */
  1857         displayIndex = SDL_GetWindowDisplayIndex(window);
  1858         if (displayIndex >= 0) {
  1859             SDL_Rect bounds;
  1860 
  1861             SDL_zero(bounds);
  1862 
  1863             SDL_GetDisplayBounds(displayIndex, &bounds);
  1864             if (x) {
  1865                 *x = bounds.x;
  1866             }
  1867             if (y) {
  1868                 *y = bounds.y;
  1869             }
  1870         }
  1871     } else {
  1872         if (x) {
  1873             *x = window->x;
  1874         }
  1875         if (y) {
  1876             *y = window->y;
  1877         }
  1878     }
  1879 }
  1880 
  1881 void
  1882 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1883 {
  1884     CHECK_WINDOW_MAGIC(window,);
  1885     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1886         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1887         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1888         if ((want != have) && (_this->SetWindowBordered)) {
  1889             if (want) {
  1890                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1891             } else {
  1892                 window->flags |= SDL_WINDOW_BORDERLESS;
  1893             }
  1894             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1895         }
  1896     }
  1897 }
  1898 
  1899 void
  1900 SDL_SetWindowResizable(SDL_Window * window, SDL_bool resizable)
  1901 {
  1902     CHECK_WINDOW_MAGIC(window,);
  1903     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1904         const int want = (resizable != SDL_FALSE);  /* normalize the flag. */
  1905         const int have = ((window->flags & SDL_WINDOW_RESIZABLE) != 0);
  1906         if ((want != have) && (_this->SetWindowResizable)) {
  1907             if (want) {
  1908                 window->flags |= SDL_WINDOW_RESIZABLE;
  1909             } else {
  1910                 window->flags &= ~SDL_WINDOW_RESIZABLE;
  1911             }
  1912             _this->SetWindowResizable(_this, window, (SDL_bool) want);
  1913         }
  1914     }
  1915 }
  1916 
  1917 void
  1918 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1919 {
  1920     CHECK_WINDOW_MAGIC(window,);
  1921     if (w <= 0) {
  1922         SDL_InvalidParamError("w");
  1923         return;
  1924     }
  1925     if (h <= 0) {
  1926         SDL_InvalidParamError("h");
  1927         return;
  1928     }
  1929 
  1930     /* Make sure we don't exceed any window size limits */
  1931     if (window->min_w && w < window->min_w) {
  1932         w = window->min_w;
  1933     }
  1934     if (window->max_w && w > window->max_w) {
  1935         w = window->max_w;
  1936     }
  1937     if (window->min_h && h < window->min_h) {
  1938         h = window->min_h;
  1939     }
  1940     if (window->max_h && h > window->max_h) {
  1941         h = window->max_h;
  1942     }
  1943 
  1944     window->windowed.w = w;
  1945     window->windowed.h = h;
  1946 
  1947     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1948         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1949             window->last_fullscreen_flags = 0;
  1950             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1951         }
  1952     } else {
  1953         window->w = w;
  1954         window->h = h;
  1955         if (_this->SetWindowSize) {
  1956             _this->SetWindowSize(_this, window);
  1957         }
  1958         if (window->w == w && window->h == h) {
  1959             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1960             SDL_OnWindowResized(window);
  1961         }
  1962     }
  1963 }
  1964 
  1965 void
  1966 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1967 {
  1968     CHECK_WINDOW_MAGIC(window,);
  1969     if (w) {
  1970         *w = window->w;
  1971     }
  1972     if (h) {
  1973         *h = window->h;
  1974     }
  1975 }
  1976 
  1977 int
  1978 SDL_GetWindowBordersSize(SDL_Window * window, int *top, int *left, int *bottom, int *right)
  1979 {
  1980     int dummy = 0;
  1981 
  1982     if (!top) { top = &dummy; }
  1983     if (!left) { left = &dummy; }
  1984     if (!right) { right = &dummy; }
  1985     if (!bottom) { bottom = &dummy; }
  1986 
  1987     /* Always initialize, so applications don't have to care */
  1988     *top = *left = *bottom = *right = 0;
  1989 
  1990     CHECK_WINDOW_MAGIC(window, -1);
  1991 
  1992     if (!_this->GetWindowBordersSize) {
  1993         return SDL_Unsupported();
  1994     }
  1995 
  1996     return _this->GetWindowBordersSize(_this, window, top, left, bottom, right);
  1997 }
  1998 
  1999 void
  2000 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  2001 {
  2002     CHECK_WINDOW_MAGIC(window,);
  2003     if (min_w <= 0) {
  2004         SDL_InvalidParamError("min_w");
  2005         return;
  2006     }
  2007     if (min_h <= 0) {
  2008         SDL_InvalidParamError("min_h");
  2009         return;
  2010     }
  2011 
  2012     if ((window->max_w && min_w >= window->max_w) ||
  2013         (window->max_h && min_h >= window->max_h)) {
  2014         SDL_SetError("SDL_SetWindowMinimumSize(): Tried to set minimum size larger than maximum size");
  2015         return;
  2016     }
  2017 
  2018     window->min_w = min_w;
  2019     window->min_h = min_h;
  2020 
  2021     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  2022         if (_this->SetWindowMinimumSize) {
  2023             _this->SetWindowMinimumSize(_this, window);
  2024         }
  2025         /* Ensure that window is not smaller than minimal size */
  2026         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  2027     }
  2028 }
  2029 
  2030 void
  2031 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  2032 {
  2033     CHECK_WINDOW_MAGIC(window,);
  2034     if (min_w) {
  2035         *min_w = window->min_w;
  2036     }
  2037     if (min_h) {
  2038         *min_h = window->min_h;
  2039     }
  2040 }
  2041 
  2042 void
  2043 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  2044 {
  2045     CHECK_WINDOW_MAGIC(window,);
  2046     if (max_w <= 0) {
  2047         SDL_InvalidParamError("max_w");
  2048         return;
  2049     }
  2050     if (max_h <= 0) {
  2051         SDL_InvalidParamError("max_h");
  2052         return;
  2053     }
  2054 
  2055     if (max_w <= window->min_w || max_h <= window->min_h) {
  2056         SDL_SetError("SDL_SetWindowMaximumSize(): Tried to set maximum size smaller than minimum size");
  2057         return;
  2058     }
  2059 
  2060     window->max_w = max_w;
  2061     window->max_h = max_h;
  2062 
  2063     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  2064         if (_this->SetWindowMaximumSize) {
  2065             _this->SetWindowMaximumSize(_this, window);
  2066         }
  2067         /* Ensure that window is not larger than maximal size */
  2068         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  2069     }
  2070 }
  2071 
  2072 void
  2073 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  2074 {
  2075     CHECK_WINDOW_MAGIC(window,);
  2076     if (max_w) {
  2077         *max_w = window->max_w;
  2078     }
  2079     if (max_h) {
  2080         *max_h = window->max_h;
  2081     }
  2082 }
  2083 
  2084 void
  2085 SDL_ShowWindow(SDL_Window * window)
  2086 {
  2087     CHECK_WINDOW_MAGIC(window,);
  2088 
  2089     if (window->flags & SDL_WINDOW_SHOWN) {
  2090         return;
  2091     }
  2092 
  2093     if (_this->ShowWindow) {
  2094         _this->ShowWindow(_this, window);
  2095     }
  2096     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  2097 }
  2098 
  2099 void
  2100 SDL_HideWindow(SDL_Window * window)
  2101 {
  2102     CHECK_WINDOW_MAGIC(window,);
  2103 
  2104     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  2105         return;
  2106     }
  2107 
  2108     window->is_hiding = SDL_TRUE;
  2109     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2110 
  2111     if (_this->HideWindow) {
  2112         _this->HideWindow(_this, window);
  2113     }
  2114     window->is_hiding = SDL_FALSE;
  2115     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  2116 }
  2117 
  2118 void
  2119 SDL_RaiseWindow(SDL_Window * window)
  2120 {
  2121     CHECK_WINDOW_MAGIC(window,);
  2122 
  2123     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  2124         return;
  2125     }
  2126     if (_this->RaiseWindow) {
  2127         _this->RaiseWindow(_this, window);
  2128     }
  2129 }
  2130 
  2131 void
  2132 SDL_MaximizeWindow(SDL_Window * window)
  2133 {
  2134     CHECK_WINDOW_MAGIC(window,);
  2135 
  2136     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  2137         return;
  2138     }
  2139 
  2140     /* !!! FIXME: should this check if the window is resizable? */
  2141 
  2142     if (_this->MaximizeWindow) {
  2143         _this->MaximizeWindow(_this, window);
  2144     }
  2145 }
  2146 
  2147 void
  2148 SDL_MinimizeWindow(SDL_Window * window)
  2149 {
  2150     CHECK_WINDOW_MAGIC(window,);
  2151 
  2152     if (window->flags & SDL_WINDOW_MINIMIZED) {
  2153         return;
  2154     }
  2155 
  2156     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2157 
  2158     if (_this->MinimizeWindow) {
  2159         _this->MinimizeWindow(_this, window);
  2160     }
  2161 }
  2162 
  2163 void
  2164 SDL_RestoreWindow(SDL_Window * window)
  2165 {
  2166     CHECK_WINDOW_MAGIC(window,);
  2167 
  2168     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  2169         return;
  2170     }
  2171 
  2172     if (_this->RestoreWindow) {
  2173         _this->RestoreWindow(_this, window);
  2174     }
  2175 }
  2176 
  2177 int
  2178 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  2179 {
  2180     Uint32 oldflags;
  2181     CHECK_WINDOW_MAGIC(window, -1);
  2182 
  2183     flags &= FULLSCREEN_MASK;
  2184 
  2185     if (flags == (window->flags & FULLSCREEN_MASK)) {
  2186         return 0;
  2187     }
  2188 
  2189     /* clear the previous flags and OR in the new ones */
  2190     oldflags = window->flags & FULLSCREEN_MASK;
  2191     window->flags &= ~FULLSCREEN_MASK;
  2192     window->flags |= flags;
  2193 
  2194     if (SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)) == 0) {
  2195         return 0;
  2196     }
  2197     
  2198     window->flags &= ~FULLSCREEN_MASK;
  2199     window->flags |= oldflags;
  2200     return -1;
  2201 }
  2202 
  2203 static SDL_Surface *
  2204 SDL_CreateWindowFramebuffer(SDL_Window * window)
  2205 {
  2206     Uint32 format;
  2207     void *pixels;
  2208     int pitch;
  2209     int bpp;
  2210     Uint32 Rmask, Gmask, Bmask, Amask;
  2211 
  2212     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  2213         return NULL;
  2214     }
  2215 
  2216     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  2217         return NULL;
  2218     }
  2219 
  2220     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  2221         return NULL;
  2222     }
  2223 
  2224     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  2225 }
  2226 
  2227 SDL_Surface *
  2228 SDL_GetWindowSurface(SDL_Window * window)
  2229 {
  2230     CHECK_WINDOW_MAGIC(window, NULL);
  2231 
  2232     if (!window->surface_valid) {
  2233         if (window->surface) {
  2234             window->surface->flags &= ~SDL_DONTFREE;
  2235             SDL_FreeSurface(window->surface);
  2236         }
  2237         window->surface = SDL_CreateWindowFramebuffer(window);
  2238         if (window->surface) {
  2239             window->surface_valid = SDL_TRUE;
  2240             window->surface->flags |= SDL_DONTFREE;
  2241         }
  2242     }
  2243     return window->surface;
  2244 }
  2245 
  2246 int
  2247 SDL_UpdateWindowSurface(SDL_Window * window)
  2248 {
  2249     SDL_Rect full_rect;
  2250 
  2251     CHECK_WINDOW_MAGIC(window, -1);
  2252 
  2253     full_rect.x = 0;
  2254     full_rect.y = 0;
  2255     full_rect.w = window->w;
  2256     full_rect.h = window->h;
  2257     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  2258 }
  2259 
  2260 int
  2261 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  2262                              int numrects)
  2263 {
  2264     CHECK_WINDOW_MAGIC(window, -1);
  2265 
  2266     if (!window->surface_valid) {
  2267         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  2268     }
  2269 
  2270     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  2271 }
  2272 
  2273 int
  2274 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  2275 {
  2276     Uint16 ramp[256];
  2277     int status;
  2278 
  2279     CHECK_WINDOW_MAGIC(window, -1);
  2280 
  2281     SDL_CalculateGammaRamp(brightness, ramp);
  2282     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  2283     if (status == 0) {
  2284         window->brightness = brightness;
  2285     }
  2286     return status;
  2287 }
  2288 
  2289 float
  2290 SDL_GetWindowBrightness(SDL_Window * window)
  2291 {
  2292     CHECK_WINDOW_MAGIC(window, 1.0f);
  2293 
  2294     return window->brightness;
  2295 }
  2296 
  2297 int
  2298 SDL_SetWindowOpacity(SDL_Window * window, float opacity)
  2299 {
  2300     int retval;
  2301     CHECK_WINDOW_MAGIC(window, -1);
  2302 
  2303     if (!_this->SetWindowOpacity) {
  2304         return SDL_Unsupported();
  2305     }
  2306 
  2307     if (opacity < 0.0f) {
  2308         opacity = 0.0f;
  2309     } else if (opacity > 1.0f) {
  2310         opacity = 1.0f;
  2311     }
  2312 
  2313     retval = _this->SetWindowOpacity(_this, window, opacity);
  2314     if (retval == 0) {
  2315         window->opacity = opacity;
  2316     }
  2317 
  2318     return retval;
  2319 }
  2320 
  2321 int
  2322 SDL_GetWindowOpacity(SDL_Window * window, float * out_opacity)
  2323 {
  2324     CHECK_WINDOW_MAGIC(window, -1);
  2325 
  2326     if (out_opacity) {
  2327         *out_opacity = window->opacity;
  2328     }
  2329 
  2330     return 0;
  2331 }
  2332 
  2333 int
  2334 SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window)
  2335 {
  2336     CHECK_WINDOW_MAGIC(modal_window, -1);
  2337     CHECK_WINDOW_MAGIC(parent_window, -1);
  2338 
  2339     if (!_this->SetWindowModalFor) {
  2340         return SDL_Unsupported();
  2341     }
  2342     
  2343     return _this->SetWindowModalFor(_this, modal_window, parent_window);
  2344 }
  2345 
  2346 int 
  2347 SDL_SetWindowInputFocus(SDL_Window * window)
  2348 {
  2349     CHECK_WINDOW_MAGIC(window, -1);
  2350 
  2351     if (!_this->SetWindowInputFocus) {
  2352         return SDL_Unsupported();
  2353     }
  2354     
  2355     return _this->SetWindowInputFocus(_this, window);
  2356 }
  2357 
  2358 
  2359 int
  2360 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  2361                                             const Uint16 * green,
  2362                                             const Uint16 * blue)
  2363 {
  2364     CHECK_WINDOW_MAGIC(window, -1);
  2365 
  2366     if (!_this->SetWindowGammaRamp) {
  2367         return SDL_Unsupported();
  2368     }
  2369 
  2370     if (!window->gamma) {
  2371         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  2372             return -1;
  2373         }
  2374         SDL_assert(window->gamma != NULL);
  2375     }
  2376 
  2377     if (red) {
  2378         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  2379     }
  2380     if (green) {
  2381         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  2382     }
  2383     if (blue) {
  2384         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  2385     }
  2386     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2387         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  2388     } else {
  2389         return 0;
  2390     }
  2391 }
  2392 
  2393 int
  2394 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  2395                                             Uint16 * green,
  2396                                             Uint16 * blue)
  2397 {
  2398     CHECK_WINDOW_MAGIC(window, -1);
  2399 
  2400     if (!window->gamma) {
  2401         int i;
  2402 
  2403         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  2404         if (!window->gamma) {
  2405             return SDL_OutOfMemory();
  2406         }
  2407         window->saved_gamma = window->gamma + 3*256;
  2408 
  2409         if (_this->GetWindowGammaRamp) {
  2410             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  2411                 return -1;
  2412             }
  2413         } else {
  2414             /* Create an identity gamma ramp */
  2415             for (i = 0; i < 256; ++i) {
  2416                 Uint16 value = (Uint16)((i << 8) | i);
  2417 
  2418                 window->gamma[0*256+i] = value;
  2419                 window->gamma[1*256+i] = value;
  2420                 window->gamma[2*256+i] = value;
  2421             }
  2422         }
  2423         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  2424     }
  2425 
  2426     if (red) {
  2427         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  2428     }
  2429     if (green) {
  2430         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  2431     }
  2432     if (blue) {
  2433         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  2434     }
  2435     return 0;
  2436 }
  2437 
  2438 void
  2439 SDL_UpdateWindowGrab(SDL_Window * window)
  2440 {
  2441     SDL_Window *grabbed_window;
  2442     SDL_bool grabbed;
  2443     if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
  2444          (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  2445         grabbed = SDL_TRUE;
  2446     } else {
  2447         grabbed = SDL_FALSE;
  2448     }
  2449 
  2450     grabbed_window = _this->grabbed_window;
  2451     if (grabbed) {
  2452         if (grabbed_window && (grabbed_window != window)) {
  2453             /* stealing a grab from another window! */
  2454             grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2455             if (_this->SetWindowGrab) {
  2456                 _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE);
  2457             }
  2458         }
  2459         _this->grabbed_window = window;
  2460     } else if (grabbed_window == window) {
  2461         _this->grabbed_window = NULL;  /* ungrabbing. */
  2462     }
  2463 
  2464     if (_this->SetWindowGrab) {
  2465         _this->SetWindowGrab(_this, window, grabbed);
  2466     }
  2467 }
  2468 
  2469 void
  2470 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  2471 {
  2472     CHECK_WINDOW_MAGIC(window,);
  2473 
  2474     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  2475         return;
  2476     }
  2477     if (grabbed) {
  2478         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  2479     } else {
  2480         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2481     }
  2482     SDL_UpdateWindowGrab(window);
  2483 }
  2484 
  2485 SDL_bool
  2486 SDL_GetWindowGrab(SDL_Window * window)
  2487 {
  2488     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2489     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
  2490     return window == _this->grabbed_window;
  2491 }
  2492 
  2493 SDL_Window *
  2494 SDL_GetGrabbedWindow(void)
  2495 {
  2496     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
  2497     return _this->grabbed_window;
  2498 }
  2499 
  2500 void
  2501 SDL_OnWindowShown(SDL_Window * window)
  2502 {
  2503     SDL_OnWindowRestored(window);
  2504 }
  2505 
  2506 void
  2507 SDL_OnWindowHidden(SDL_Window * window)
  2508 {
  2509     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2510 }
  2511 
  2512 void
  2513 SDL_OnWindowResized(SDL_Window * window)
  2514 {
  2515     window->surface_valid = SDL_FALSE;
  2516     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2517 }
  2518 
  2519 void
  2520 SDL_OnWindowMinimized(SDL_Window * window)
  2521 {
  2522     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2523 }
  2524 
  2525 void
  2526 SDL_OnWindowRestored(SDL_Window * window)
  2527 {
  2528     /*
  2529      * FIXME: Is this fine to just remove this, or should it be preserved just
  2530      * for the fullscreen case? In principle it seems like just hiding/showing
  2531      * windows shouldn't affect the stacking order; maybe the right fix is to
  2532      * re-decouple OnWindowShown and OnWindowRestored.
  2533      */
  2534     /*SDL_RaiseWindow(window);*/
  2535 
  2536     if (FULLSCREEN_VISIBLE(window)) {
  2537         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2538     }
  2539 }
  2540 
  2541 void
  2542 SDL_OnWindowEnter(SDL_Window * window)
  2543 {
  2544     if (_this->OnWindowEnter) {
  2545         _this->OnWindowEnter(_this, window);
  2546     }
  2547 }
  2548 
  2549 void
  2550 SDL_OnWindowLeave(SDL_Window * window)
  2551 {
  2552 }
  2553 
  2554 void
  2555 SDL_OnWindowFocusGained(SDL_Window * window)
  2556 {
  2557     SDL_Mouse *mouse = SDL_GetMouse();
  2558 
  2559     if (window->gamma && _this->SetWindowGammaRamp) {
  2560         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2561     }
  2562 
  2563     if (mouse && mouse->relative_mode) {
  2564         SDL_SetMouseFocus(window);
  2565         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2566     }
  2567 
  2568     SDL_UpdateWindowGrab(window);
  2569 }
  2570 
  2571 static SDL_bool
  2572 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2573 {
  2574     if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
  2575         return SDL_FALSE;
  2576     }
  2577 
  2578 #ifdef __MACOSX__
  2579     if (SDL_strcmp(_this->name, "cocoa") == 0) {  /* don't do this for X11, etc */
  2580         if (Cocoa_IsWindowInFullscreenSpace(window)) {
  2581             return SDL_FALSE;
  2582         }
  2583     }
  2584 #endif
  2585 
  2586     return SDL_GetHintBoolean(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, SDL_TRUE);
  2587 }
  2588 
  2589 void
  2590 SDL_OnWindowFocusLost(SDL_Window * window)
  2591 {
  2592     if (window->gamma && _this->SetWindowGammaRamp) {
  2593         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2594     }
  2595 
  2596     SDL_UpdateWindowGrab(window);
  2597 
  2598     if (ShouldMinimizeOnFocusLoss(window)) {
  2599         SDL_MinimizeWindow(window);
  2600     }
  2601 }
  2602 
  2603 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
  2604    !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
  2605 SDL_Window *
  2606 SDL_GetFocusWindow(void)
  2607 {
  2608     SDL_Window *window;
  2609 
  2610     if (!_this) {
  2611         return NULL;
  2612     }
  2613     for (window = _this->windows; window; window = window->next) {
  2614         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2615             return window;
  2616         }
  2617     }
  2618     return NULL;
  2619 }
  2620 
  2621 void
  2622 SDL_DestroyWindow(SDL_Window * window)
  2623 {
  2624     SDL_VideoDisplay *display;
  2625 
  2626     CHECK_WINDOW_MAGIC(window,);
  2627 
  2628     window->is_destroying = SDL_TRUE;
  2629 
  2630     /* Restore video mode, etc. */
  2631     SDL_HideWindow(window);
  2632 
  2633     /* Make sure this window no longer has focus */
  2634     if (SDL_GetKeyboardFocus() == window) {
  2635         SDL_SetKeyboardFocus(NULL);
  2636     }
  2637     if (SDL_GetMouseFocus() == window) {
  2638         SDL_SetMouseFocus(NULL);
  2639     }
  2640 
  2641     /* make no context current if this is the current context window. */
  2642     if (window->flags & SDL_WINDOW_OPENGL) {
  2643         if (_this->current_glwin == window) {
  2644             SDL_GL_MakeCurrent(window, NULL);
  2645         }
  2646     }
  2647 
  2648     if (window->surface) {
  2649         window->surface->flags &= ~SDL_DONTFREE;
  2650         SDL_FreeSurface(window->surface);
  2651     }
  2652     if (_this->DestroyWindowFramebuffer) {
  2653         _this->DestroyWindowFramebuffer(_this, window);
  2654     }
  2655     if (_this->DestroyWindow) {
  2656         _this->DestroyWindow(_this, window);
  2657     }
  2658     if (window->flags & SDL_WINDOW_OPENGL) {
  2659         SDL_GL_UnloadLibrary();
  2660     }
  2661     if (window->flags & SDL_WINDOW_VULKAN) {
  2662         SDL_Vulkan_UnloadLibrary();
  2663     }
  2664 
  2665     display = SDL_GetDisplayForWindow(window);
  2666     if (display->fullscreen_window == window) {
  2667         display->fullscreen_window = NULL;
  2668     }
  2669 
  2670     /* Now invalidate magic */
  2671     window->magic = NULL;
  2672 
  2673     /* Free memory associated with the window */
  2674     SDL_free(window->title);
  2675     SDL_FreeSurface(window->icon);
  2676     SDL_free(window->gamma);
  2677     while (window->data) {
  2678         SDL_WindowUserData *data = window->data;
  2679 
  2680         window->data = data->next;
  2681         SDL_free(data->name);
  2682         SDL_free(data);
  2683     }
  2684 
  2685     /* Unlink the window from the list */
  2686     if (window->next) {
  2687         window->next->prev = window->prev;
  2688     }
  2689     if (window->prev) {
  2690         window->prev->next = window->next;
  2691     } else {
  2692         _this->windows = window->next;
  2693     }
  2694 
  2695     SDL_free(window);
  2696 }
  2697 
  2698 SDL_bool
  2699 SDL_IsScreenSaverEnabled()
  2700 {
  2701     if (!_this) {
  2702         return SDL_TRUE;
  2703     }
  2704     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2705 }
  2706 
  2707 void
  2708 SDL_EnableScreenSaver()
  2709 {
  2710     if (!_this) {
  2711         return;
  2712     }
  2713     if (!_this->suspend_screensaver) {
  2714         return;
  2715     }
  2716     _this->suspend_screensaver = SDL_FALSE;
  2717     if (_this->SuspendScreenSaver) {
  2718         _this->SuspendScreenSaver(_this);
  2719     }
  2720 }
  2721 
  2722 void
  2723 SDL_DisableScreenSaver()
  2724 {
  2725     if (!_this) {
  2726         return;
  2727     }
  2728     if (_this->suspend_screensaver) {
  2729         return;
  2730     }
  2731     _this->suspend_screensaver = SDL_TRUE;
  2732     if (_this->SuspendScreenSaver) {
  2733         _this->SuspendScreenSaver(_this);
  2734     }
  2735 }
  2736 
  2737 void
  2738 SDL_VideoQuit(void)
  2739 {
  2740     int i, j;
  2741 
  2742     if (!_this) {
  2743         return;
  2744     }
  2745 
  2746     /* Halt event processing before doing anything else */
  2747     SDL_TouchQuit();
  2748     SDL_MouseQuit();
  2749     SDL_KeyboardQuit();
  2750     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2751 
  2752     SDL_EnableScreenSaver();
  2753 
  2754     /* Clean up the system video */
  2755     while (_this->windows) {
  2756         SDL_DestroyWindow(_this->windows);
  2757     }
  2758     _this->VideoQuit(_this);
  2759 
  2760     for (i = 0; i < _this->num_displays; ++i) {
  2761         SDL_VideoDisplay *display = &_this->displays[i];
  2762         for (j = display->num_display_modes; j--;) {
  2763             SDL_free(display->display_modes[j].driverdata);
  2764             display->display_modes[j].driverdata = NULL;
  2765         }
  2766         SDL_free(display->display_modes);
  2767         display->display_modes = NULL;
  2768         SDL_free(display->desktop_mode.driverdata);
  2769         display->desktop_mode.driverdata = NULL;
  2770         SDL_free(display->driverdata);
  2771         display->driverdata = NULL;
  2772     }
  2773     if (_this->displays) {
  2774         for (i = 0; i < _this->num_displays; ++i) {
  2775             SDL_free(_this->displays[i].name);
  2776         }
  2777         SDL_free(_this->displays);
  2778         _this->displays = NULL;
  2779         _this->num_displays = 0;
  2780     }
  2781     SDL_free(_this->clipboard_text);
  2782     _this->clipboard_text = NULL;
  2783     _this->free(_this);
  2784     _this = NULL;
  2785 }
  2786 
  2787 int
  2788 SDL_GL_LoadLibrary(const char *path)
  2789 {
  2790     int retval;
  2791 
  2792     if (!_this) {
  2793         return SDL_UninitializedVideo();
  2794     }
  2795     if (_this->gl_config.driver_loaded) {
  2796         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2797             return SDL_SetError("OpenGL library already loaded");
  2798         }
  2799         retval = 0;
  2800     } else {
  2801         if (!_this->GL_LoadLibrary) {
  2802             return SDL_SetError("No dynamic GL support in current SDL video driver (%s)", _this->name);
  2803         }
  2804         retval = _this->GL_LoadLibrary(_this, path);
  2805     }
  2806     if (retval == 0) {
  2807         ++_this->gl_config.driver_loaded;
  2808     } else {
  2809         if (_this->GL_UnloadLibrary) {
  2810             _this->GL_UnloadLibrary(_this);
  2811         }
  2812     }
  2813     return (retval);
  2814 }
  2815 
  2816 void *
  2817 SDL_GL_GetProcAddress(const char *proc)
  2818 {
  2819     void *func;
  2820 
  2821     if (!_this) {
  2822         SDL_UninitializedVideo();
  2823         return NULL;
  2824     }
  2825     func = NULL;
  2826     if (_this->GL_GetProcAddress) {
  2827         if (_this->gl_config.driver_loaded) {
  2828             func = _this->GL_GetProcAddress(_this, proc);
  2829         } else {
  2830             SDL_SetError("No GL driver has been loaded");
  2831         }
  2832     } else {
  2833         SDL_SetError("No dynamic GL support in current SDL video driver (%s)", _this->name);
  2834     }
  2835     return func;
  2836 }
  2837 
  2838 void
  2839 SDL_GL_UnloadLibrary(void)
  2840 {
  2841     if (!_this) {
  2842         SDL_UninitializedVideo();
  2843         return;
  2844     }
  2845     if (_this->gl_config.driver_loaded > 0) {
  2846         if (--_this->gl_config.driver_loaded > 0) {
  2847             return;
  2848         }
  2849         if (_this->GL_UnloadLibrary) {
  2850             _this->GL_UnloadLibrary(_this);
  2851         }
  2852     }
  2853 }
  2854 
  2855 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2856 static SDL_INLINE SDL_bool
  2857 isAtLeastGL3(const char *verstr)
  2858 {
  2859     return (verstr && (SDL_atoi(verstr) >= 3));
  2860 }
  2861 #endif
  2862 
  2863 SDL_bool
  2864 SDL_GL_ExtensionSupported(const char *extension)
  2865 {
  2866 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2867     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2868     const char *extensions;
  2869     const char *start;
  2870     const char *where, *terminator;
  2871 
  2872     /* Extension names should not have spaces. */
  2873     where = SDL_strchr(extension, ' ');
  2874     if (where || *extension == '\0') {
  2875         return SDL_FALSE;
  2876     }
  2877     /* See if there's an environment variable override */
  2878     start = SDL_getenv(extension);
  2879     if (start && *start == '0') {
  2880         return SDL_FALSE;
  2881     }
  2882 
  2883     /* Lookup the available extensions */
  2884 
  2885     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2886     if (!glGetStringFunc) {
  2887         return SDL_FALSE;
  2888     }
  2889 
  2890     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2891         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2892         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2893         GLint num_exts = 0;
  2894         GLint i;
  2895 
  2896         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2897         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2898         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2899             return SDL_FALSE;
  2900         }
  2901 
  2902         #ifndef GL_NUM_EXTENSIONS
  2903         #define GL_NUM_EXTENSIONS 0x821D
  2904         #endif
  2905         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2906         for (i = 0; i < num_exts; i++) {
  2907             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2908             if (SDL_strcmp(thisext, extension) == 0) {
  2909                 return SDL_TRUE;
  2910             }
  2911         }
  2912 
  2913         return SDL_FALSE;
  2914     }
  2915 
  2916     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2917 
  2918     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2919     if (!extensions) {
  2920         return SDL_FALSE;
  2921     }
  2922     /*
  2923      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2924      * extensions string. Don't be fooled by sub-strings, etc.
  2925      */
  2926 
  2927     start = extensions;
  2928 
  2929     for (;;) {
  2930         where = SDL_strstr(start, extension);
  2931         if (!where)
  2932             break;
  2933 
  2934         terminator = where + SDL_strlen(extension);
  2935         if (where == extensions || *(where - 1) == ' ')
  2936             if (*terminator == ' ' || *terminator == '\0')
  2937                 return SDL_TRUE;
  2938 
  2939         start = terminator;
  2940     }
  2941     return SDL_FALSE;
  2942 #else
  2943     return SDL_FALSE;
  2944 #endif
  2945 }
  2946 
  2947 /* Deduce supported ES profile versions from the supported
  2948    ARB_ES*_compatibility extensions. There is no direct query.
  2949    
  2950    This is normally only called when the OpenGL driver supports
  2951    {GLX,WGL}_EXT_create_context_es2_profile.
  2952  */
  2953 void
  2954 SDL_GL_DeduceMaxSupportedESProfile(int* major, int* minor)
  2955 {
  2956 /* THIS REQUIRES AN EXISTING GL CONTEXT THAT HAS BEEN MADE CURRENT. */
  2957 /*  Please refer to https://bugzilla.libsdl.org/show_bug.cgi?id=3725 for discussion. */
  2958 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2959     /* XXX This is fragile; it will break in the event of release of
  2960      * new versions of OpenGL ES.
  2961      */
  2962     if (SDL_GL_ExtensionSupported("GL_ARB_ES3_2_compatibility")) {
  2963         *major = 3;
  2964         *minor = 2;
  2965     } else if (SDL_GL_ExtensionSupported("GL_ARB_ES3_1_compatibility")) {
  2966         *major = 3;
  2967         *minor = 1;
  2968     } else if (SDL_GL_ExtensionSupported("GL_ARB_ES3_compatibility")) {
  2969         *major = 3;
  2970         *minor = 0;
  2971     } else {
  2972         *major = 2;
  2973         *minor = 0;
  2974     }
  2975 #endif
  2976 }
  2977 
  2978 void
  2979 SDL_GL_ResetAttributes()
  2980 {
  2981     if (!_this) {
  2982         return;
  2983     }
  2984 
  2985     _this->gl_config.red_size = 3;
  2986     _this->gl_config.green_size = 3;
  2987     _this->gl_config.blue_size = 2;
  2988     _this->gl_config.alpha_size = 0;
  2989     _this->gl_config.buffer_size = 0;
  2990     _this->gl_config.depth_size = 16;
  2991     _this->gl_config.stencil_size = 0;
  2992     _this->gl_config.double_buffer = 1;
  2993     _this->gl_config.accum_red_size = 0;
  2994     _this->gl_config.accum_green_size = 0;
  2995     _this->gl_config.accum_blue_size = 0;
  2996     _this->gl_config.accum_alpha_size = 0;
  2997     _this->gl_config.stereo = 0;
  2998     _this->gl_config.multisamplebuffers = 0;
  2999     _this->gl_config.multisamplesamples = 0;
  3000     _this->gl_config.retained_backing = 1;
  3001     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
  3002 
  3003     if (_this->GL_DefaultProfileConfig) {
  3004         _this->GL_DefaultProfileConfig(_this, &_this->gl_config.profile_mask,
  3005                                        &_this->gl_config.major_version,
  3006                                        &_this->gl_config.minor_version);
  3007     } else {
  3008 #if SDL_VIDEO_OPENGL
  3009         _this->gl_config.major_version = 2;
  3010         _this->gl_config.minor_version = 1;
  3011         _this->gl_config.profile_mask = 0;
  3012 #elif SDL_VIDEO_OPENGL_ES2
  3013         _this->gl_config.major_version = 2;
  3014         _this->gl_config.minor_version = 0;
  3015         _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  3016 #elif SDL_VIDEO_OPENGL_ES
  3017         _this->gl_config.major_version = 1;
  3018         _this->gl_config.minor_version = 1;
  3019         _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  3020 #endif
  3021     }
  3022 
  3023     _this->gl_config.flags = 0;
  3024     _this->gl_config.framebuffer_srgb_capable = 0;
  3025     _this->gl_config.no_error = 0;
  3026     _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
  3027     _this->gl_config.reset_notification = SDL_GL_CONTEXT_RESET_NO_NOTIFICATION;
  3028 
  3029     _this->gl_config.share_with_current_context = 0;
  3030 }
  3031 
  3032 int
  3033 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  3034 {
  3035 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  3036     int retval;
  3037 
  3038     if (!_this) {
  3039         return SDL_UninitializedVideo();
  3040     }
  3041     retval = 0;
  3042     switch (attr) {
  3043     case SDL_GL_RED_SIZE:
  3044         _this->gl_config.red_size = value;
  3045         break;
  3046     case SDL_GL_GREEN_SIZE:
  3047         _this->gl_config.green_size = value;
  3048         break;
  3049     case SDL_GL_BLUE_SIZE:
  3050         _this->gl_config.blue_size = value;
  3051         break;
  3052     case SDL_GL_ALPHA_SIZE:
  3053         _this->gl_config.alpha_size = value;
  3054         break;
  3055     case SDL_GL_DOUBLEBUFFER:
  3056         _this->gl_config.double_buffer = value;
  3057         break;
  3058     case SDL_GL_BUFFER_SIZE:
  3059         _this->gl_config.buffer_size = value;
  3060         break;
  3061     case SDL_GL_DEPTH_SIZE:
  3062         _this->gl_config.depth_size = value;
  3063         break;
  3064     case SDL_GL_STENCIL_SIZE:
  3065         _this->gl_config.stencil_size = value;
  3066         break;
  3067     case SDL_GL_ACCUM_RED_SIZE:
  3068         _this->gl_config.accum_red_size = value;
  3069         break;
  3070     case SDL_GL_ACCUM_GREEN_SIZE:
  3071         _this->gl_config.accum_green_size = value;
  3072         break;
  3073     case SDL_GL_ACCUM_BLUE_SIZE:
  3074         _this->gl_config.accum_blue_size = value;
  3075         break;
  3076     case SDL_GL_ACCUM_ALPHA_SIZE:
  3077         _this->gl_config.accum_alpha_size = value;
  3078         break;
  3079     case SDL_GL_STEREO:
  3080         _this->gl_config.stereo = value;
  3081         break;
  3082     case SDL_GL_MULTISAMPLEBUFFERS:
  3083         _this->gl_config.multisamplebuffers = value;
  3084         break;
  3085     case SDL_GL_MULTISAMPLESAMPLES:
  3086         _this->gl_config.multisamplesamples = value;
  3087         break;
  3088     case SDL_GL_ACCELERATED_VISUAL:
  3089         _this->gl_config.accelerated = value;
  3090         break;
  3091     case SDL_GL_RETAINED_BACKING:
  3092         _this->gl_config.retained_backing = value;
  3093         break;
  3094     case SDL_GL_CONTEXT_MAJOR_VERSION:
  3095         _this->gl_config.major_version = value;
  3096         break;
  3097     case SDL_GL_CONTEXT_MINOR_VERSION:
  3098         _this->gl_config.minor_version = value;
  3099         break;
  3100     case SDL_GL_CONTEXT_EGL:
  3101         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  3102         if (value != 0) {
  3103             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  3104         } else {
  3105             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  3106         };
  3107         break;
  3108     case SDL_GL_CONTEXT_FLAGS:
  3109         if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  3110                       SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  3111                       SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  3112                       SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
  3113             retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  3114             break;
  3115         }
  3116         _this->gl_config.flags = value;
  3117         break;
  3118     case SDL_GL_CONTEXT_PROFILE_MASK:
  3119         if (value != 0 &&
  3120             value != SDL_GL_CONTEXT_PROFILE_CORE &&
  3121             value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  3122             value != SDL_GL_CONTEXT_PROFILE_ES) {
  3123             retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  3124             break;
  3125         }
  3126         _this->gl_config.profile_mask = value;
  3127         break;
  3128     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  3129         _this->gl_config.share_with_current_context = value;
  3130         break;
  3131     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  3132         _this->gl_config.framebuffer_srgb_capable = value;
  3133         break;
  3134     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
  3135         _this->gl_config.release_behavior = value;
  3136         break;
  3137     case SDL_GL_CONTEXT_RESET_NOTIFICATION:
  3138         _this->gl_config.reset_notification = value;
  3139         break;
  3140     case SDL_GL_CONTEXT_NO_ERROR:
  3141         _this->gl_config.no_error = value;
  3142         break;
  3143     default:
  3144         retval = SDL_SetError("Unknown OpenGL attribute");
  3145         break;
  3146     }
  3147     return retval;
  3148 #else
  3149     return SDL_Unsupported();
  3150 #endif /* SDL_VIDEO_OPENGL */
  3151 }
  3152 
  3153 int
  3154 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  3155 {
  3156 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  3157     GLenum (APIENTRY *glGetErrorFunc) (void);
  3158     GLenum attrib = 0;
  3159     GLenum error = 0;
  3160 
  3161     /*
  3162      * Some queries in Core Profile desktop OpenGL 3+ contexts require
  3163      * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that
  3164      * the enums we use for the former function don't exist in OpenGL ES 2, and
  3165      * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2.
  3166      */
  3167 #if SDL_VIDEO_OPENGL
  3168     const GLubyte *(APIENTRY *glGetStringFunc) (GLenum name);
  3169     void (APIENTRY *glGetFramebufferAttachmentParameterivFunc) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
  3170     GLenum attachment = GL_BACK_LEFT;
  3171     GLenum attachmentattrib = 0;
  3172 #endif
  3173 
  3174     if (!value) {
  3175         return SDL_InvalidParamError("value");
  3176     }
  3177 
  3178     /* Clear value in any case */
  3179     *value = 0;
  3180 
  3181     if (!_this) {
  3182         return SDL_UninitializedVideo();
  3183     }
  3184 
  3185     switch (attr) {
  3186     case SDL_GL_RED_SIZE:
  3187 #if SDL_VIDEO_OPENGL
  3188         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
  3189 #endif
  3190         attrib = GL_RED_BITS;
  3191         break;
  3192     case SDL_GL_BLUE_SIZE:
  3193 #if SDL_VIDEO_OPENGL
  3194         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
  3195 #endif
  3196         attrib = GL_BLUE_BITS;
  3197         break;
  3198     case SDL_GL_GREEN_SIZE:
  3199 #if SDL_VIDEO_OPENGL
  3200         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
  3201 #endif
  3202         attrib = GL_GREEN_BITS;
  3203         break;
  3204     case SDL_GL_ALPHA_SIZE:
  3205 #if SDL_VIDEO_OPENGL
  3206         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
  3207 #endif
  3208         attrib = GL_ALPHA_BITS;
  3209         break;
  3210     case SDL_GL_DOUBLEBUFFER:
  3211 #if SDL_VIDEO_OPENGL
  3212         attrib = GL_DOUBLEBUFFER;
  3213         break;
  3214 #else
  3215         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  3216         /* parameter which switches double buffer to single buffer. OpenGL ES */
  3217         /* SDL driver must set proper value after initialization              */
  3218         *value = _this->gl_config.double_buffer;
  3219         return 0;
  3220 #endif
  3221     case SDL_GL_DEPTH_SIZE:
  3222 #if SDL_VIDEO_OPENGL
  3223         attachment = GL_DEPTH;
  3224         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE;
  3225 #endif
  3226         attrib = GL_DEPTH_BITS;
  3227         break;
  3228     case SDL_GL_STENCIL_SIZE:
  3229 #if SDL_VIDEO_OPENGL
  3230         attachment = GL_STENCIL;
  3231         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE;
  3232 #endif
  3233         attrib = GL_STENCIL_BITS;
  3234         break;
  3235 #if SDL_VIDEO_OPENGL
  3236     case SDL_GL_ACCUM_RED_SIZE:
  3237         attrib = GL_ACCUM_RED_BITS;
  3238         break;
  3239     case SDL_GL_ACCUM_GREEN_SIZE:
  3240         attrib = GL_ACCUM_GREEN_BITS;
  3241         break;
  3242     case SDL_GL_ACCUM_BLUE_SIZE:
  3243         attrib = GL_ACCUM_BLUE_BITS;
  3244         break;
  3245     case SDL_GL_ACCUM_ALPHA_SIZE:
  3246         attrib = GL_ACCUM_ALPHA_BITS;
  3247         break;
  3248     case SDL_GL_STEREO:
  3249         attrib = GL_STEREO;
  3250         break;
  3251 #else
  3252     case SDL_GL_ACCUM_RED_SIZE:
  3253     case SDL_GL_ACCUM_GREEN_SIZE:
  3254     case SDL_GL_ACCUM_BLUE_SIZE:
  3255     case SDL_GL_ACCUM_ALPHA_SIZE:
  3256     case SDL_GL_STEREO:
  3257         /* none of these are supported in OpenGL ES */
  3258         *value = 0;
  3259         return 0;
  3260 #endif
  3261     case SDL_GL_MULTISAMPLEBUFFERS:
  3262         attrib = GL_SAMPLE_BUFFERS;
  3263         break;
  3264     case SDL_GL_MULTISAMPLESAMPLES:
  3265         attrib = GL_SAMPLES;
  3266         break;
  3267     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
  3268 #if SDL_VIDEO_OPENGL
  3269         attrib = GL_CONTEXT_RELEASE_BEHAVIOR;
  3270 #else
  3271         attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR;
  3272 #endif
  3273         break;
  3274     case SDL_GL_BUFFER_SIZE:
  3275         {
  3276             int rsize = 0, gsize = 0, bsize = 0, asize = 0;
  3277 
  3278             /* There doesn't seem to be a single flag in OpenGL for this! */
  3279             if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize) < 0) {
  3280                 return -1;
  3281             }
  3282             if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize) < 0) {
  3283                 return -1;
  3284             }
  3285             if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize) < 0) {
  3286                 return -1;
  3287             }
  3288             if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize) < 0) {
  3289                 return -1;
  3290             }
  3291 
  3292             *value = rsize + gsize + bsize + asize;
  3293             return 0;
  3294         }
  3295     case SDL_GL_ACCELERATED_VISUAL:
  3296         {
  3297             /* FIXME: How do we get this information? */
  3298             *value = (_this->gl_config.accelerated != 0);
  3299             return 0;
  3300         }
  3301     case SDL_GL_RETAINED_BACKING:
  3302         {
  3303             *value = _this->gl_config.retained_backing;
  3304             return 0;
  3305         }
  3306     case SDL_GL_CONTEXT_MAJOR_VERSION:
  3307         {
  3308             *value = _this->gl_config.major_version;
  3309             return 0;
  3310         }
  3311     case SDL_GL_CONTEXT_MINOR_VERSION:
  3312         {
  3313             *value = _this->gl_config.minor_version;
  3314             return 0;
  3315         }
  3316     case SDL_GL_CONTEXT_EGL:
  3317         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  3318         {
  3319             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  3320                 *value = 1;
  3321             }
  3322             else {
  3323                 *value = 0;
  3324             }
  3325             return 0;
  3326         }
  3327     case SDL_GL_CONTEXT_FLAGS:
  3328         {
  3329             *value = _this->gl_config.flags;
  3330             return 0;
  3331         }
  3332     case SDL_GL_CONTEXT_PROFILE_MASK:
  3333         {
  3334             *value = _this->gl_config.profile_mask;
  3335             return 0;
  3336         }
  3337     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  3338         {
  3339             *value = _this->gl_config.share_with_current_context;
  3340             return 0;
  3341         }
  3342     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  3343         {
  3344             *value = _this->gl_config.framebuffer_srgb_capable;
  3345             return 0;
  3346         }
  3347     case SDL_GL_CONTEXT_NO_ERROR:
  3348         {
  3349             *value = _this->gl_config.no_error;
  3350             return 0;
  3351         }
  3352     default:
  3353         return SDL_SetError("Unknown OpenGL attribute");
  3354     }
  3355 
  3356 #if SDL_VIDEO_OPENGL
  3357     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  3358     if (!glGetStringFunc) {
  3359         return -1;
  3360     }
  3361 
  3362     if (attachmentattrib && isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  3363         glGetFramebufferAttachmentParameterivFunc = SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv");
  3364 
  3365         if (glGetFramebufferAttachmentParameterivFunc) {
  3366             glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *) value);
  3367         } else {
  3368             return -1;
  3369         }
  3370     } else
  3371 #endif
  3372     {
  3373         void (APIENTRY *glGetIntegervFunc) (GLenum pname, GLint * params);
  3374         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  3375         if (glGetIntegervFunc) {
  3376             glGetIntegervFunc(attrib, (GLint *) value);
  3377         } else {
  3378             return -1;
  3379         }
  3380     }
  3381 
  3382     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  3383     if (!glGetErrorFunc) {
  3384         return -1;
  3385     }
  3386 
  3387     error = glGetErrorFunc();
  3388     if (error != GL_NO_ERROR) {
  3389         if (error == GL_INVALID_ENUM) {
  3390             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  3391         } else if (error == GL_INVALID_VALUE) {
  3392             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  3393         }
  3394         return SDL_SetError("OpenGL error: %08X", error);
  3395     }
  3396     return 0;
  3397 #else
  3398     return SDL_Unsupported();
  3399 #endif /* SDL_VIDEO_OPENGL */
  3400 }
  3401 
  3402 SDL_GLContext
  3403 SDL_GL_CreateContext(SDL_Window * window)
  3404 {
  3405     SDL_GLContext ctx = NULL;
  3406     CHECK_WINDOW_MAGIC(window, NULL);
  3407 
  3408     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3409         SDL_SetError("The specified window isn't an OpenGL window");
  3410         return NULL;
  3411     }
  3412 
  3413     ctx = _this->GL_CreateContext(_this, window);
  3414 
  3415     /* Creating a context is assumed to make it current in the SDL driver. */
  3416     if (ctx) {
  3417         _this->current_glwin = window;
  3418         _this->current_glctx = ctx;
  3419         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  3420         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  3421     }
  3422     return ctx;
  3423 }
  3424 
  3425 int
  3426 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  3427 {
  3428     int retval;
  3429 
  3430     if (window == SDL_GL_GetCurrentWindow() &&
  3431         ctx == SDL_GL_GetCurrentContext()) {
  3432         /* We're already current. */
  3433         return 0;
  3434     }
  3435 
  3436     if (!ctx) {
  3437         window = NULL;
  3438     } else {
  3439         CHECK_WINDOW_MAGIC(window, -1);
  3440 
  3441         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3442             return SDL_SetError("The specified window isn't an OpenGL window");
  3443         }
  3444     }
  3445 
  3446     retval = _this->GL_MakeCurrent(_this, window, ctx);
  3447     if (retval == 0) {
  3448         _this->current_glwin = window;
  3449         _this->current_glctx = ctx;
  3450         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  3451         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  3452     }
  3453     return retval;
  3454 }
  3455 
  3456 SDL_Window *
  3457 SDL_GL_GetCurrentWindow(void)
  3458 {
  3459     if (!_this) {
  3460         SDL_UninitializedVideo();
  3461         return NULL;
  3462     }
  3463     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  3464 }
  3465 
  3466 SDL_GLContext
  3467 SDL_GL_GetCurrentContext(void)
  3468 {
  3469     if (!_this) {
  3470         SDL_UninitializedVideo();
  3471         return NULL;
  3472     }
  3473     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  3474 }
  3475 
  3476 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  3477 {
  3478     CHECK_WINDOW_MAGIC(window,);
  3479 
  3480     if (_this->GL_GetDrawableSize) {
  3481         _this->GL_GetDrawableSize(_this, window, w, h);
  3482     } else {
  3483         SDL_GetWindowSize(window, w, h);
  3484     }
  3485 }
  3486 
  3487 int
  3488 SDL_GL_SetSwapInterval(int interval)
  3489 {
  3490     if (!_this) {
  3491         return SDL_UninitializedVideo();
  3492     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3493         return SDL_SetError("No OpenGL context has been made current");
  3494     } else if (_this->GL_SetSwapInterval) {
  3495         return _this->GL_SetSwapInterval(_this, interval);
  3496     } else {
  3497         return SDL_SetError("Setting the swap interval is not supported");
  3498     }
  3499 }
  3500 
  3501 int
  3502 SDL_GL_GetSwapInterval(void)
  3503 {
  3504     if (!_this) {
  3505         return 0;
  3506     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3507         return 0;
  3508     } else if (_this->GL_GetSwapInterval) {
  3509         return _this->GL_GetSwapInterval(_this);
  3510     } else {
  3511         return 0;
  3512     }
  3513 }
  3514 
  3515 void
  3516 SDL_GL_SwapWindow(SDL_Window * window)
  3517 {
  3518     CHECK_WINDOW_MAGIC(window,);
  3519 
  3520     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3521         SDL_SetError("The specified window isn't an OpenGL window");
  3522         return;
  3523     }
  3524 
  3525     if (SDL_GL_GetCurrentWindow() != window) {
  3526         SDL_SetError("The specified window has not been made current");
  3527         return;
  3528     }
  3529 
  3530     _this->GL_SwapWindow(_this, window);
  3531 }
  3532 
  3533 void
  3534 SDL_GL_DeleteContext(SDL_GLContext context)
  3535 {
  3536     if (!_this || !context) {
  3537         return;
  3538     }
  3539 
  3540     if (SDL_GL_GetCurrentContext() == context) {
  3541         SDL_GL_MakeCurrent(NULL, NULL);
  3542     }
  3543 
  3544     _this->GL_DeleteContext(_this, context);
  3545 }
  3546 
  3547 #if 0                           /* FIXME */
  3548 /*
  3549  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  3550  * & 2 for alpha channel.
  3551  */
  3552 static void
  3553 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  3554 {
  3555     int x, y;
  3556     Uint32 colorkey;
  3557 #define SET_MASKBIT(icon, x, y, mask) \
  3558     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  3559 
  3560     colorkey = icon->format->colorkey;
  3561     switch (icon->format->BytesPerPixel) {
  3562     case 1:
  3563         {
  3564             Uint8 *pixels;
  3565             for (y = 0; y < icon->h; ++y) {
  3566                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  3567                 for (x = 0; x < icon->w; ++x) {
  3568                     if (*pixels++ == colorkey) {
  3569                         SET_MASKBIT(icon, x, y, mask);
  3570                     }
  3571                 }
  3572             }
  3573         }
  3574         break;
  3575 
  3576     case 2:
  3577         {
  3578             Uint16 *pixels;
  3579             for (y = 0; y < icon->h; ++y) {
  3580                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3581                 for (x = 0; x < icon->w; ++x) {
  3582                     if ((flags & 1) && *pixels == colorkey) {
  3583                         SET_MASKBIT(icon, x, y, mask);
  3584                     } else if ((flags & 2)
  3585                                && (*pixels & icon->format->Amask) == 0) {
  3586                         SET_MASKBIT(icon, x, y, mask);
  3587                     }
  3588                     pixels++;
  3589                 }
  3590             }
  3591         }
  3592         break;
  3593 
  3594     case 4:
  3595         {
  3596             Uint32 *pixels;
  3597             for (y = 0; y < icon->h; ++y) {
  3598                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3599                 for (x = 0; x < icon->w; ++x) {
  3600                     if ((flags & 1) && *pixels == colorkey) {
  3601                         SET_MASKBIT(icon, x, y, mask);
  3602                     } else if ((flags & 2)
  3603                                && (*pixels & icon->format->Amask) == 0) {
  3604                         SET_MASKBIT(icon, x, y, mask);
  3605                     }
  3606                     pixels++;
  3607                 }
  3608             }
  3609         }
  3610         break;
  3611     }
  3612 }
  3613 
  3614 /*
  3615  * Sets the window manager icon for the display window.
  3616  */
  3617 void
  3618 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3619 {
  3620     if (icon && _this->SetIcon) {
  3621         /* Generate a mask if necessary, and create the icon! */
  3622         if (mask == NULL) {
  3623             int mask_len = icon->h * (icon->w + 7) / 8;
  3624             int flags = 0;
  3625             mask = (Uint8 *) SDL_malloc(mask_len);
  3626             if (mask == NULL) {
  3627                 return;
  3628             }
  3629             SDL_memset(mask, ~0, mask_len);
  3630             if (icon->flags & SDL_SRCCOLORKEY)
  3631                 flags |= 1;
  3632             if (icon->flags & SDL_SRCALPHA)
  3633                 flags |= 2;
  3634             if (flags) {
  3635                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3636             }
  3637             _this->SetIcon(_this, icon, mask);
  3638             SDL_free(mask);
  3639         } else {
  3640             _this->SetIcon(_this, icon, mask);
  3641         }
  3642     }
  3643 }
  3644 #endif
  3645 
  3646 SDL_bool
  3647 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3648 {
  3649     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3650 
  3651     if (!info) {
  3652         SDL_InvalidParamError("info");
  3653         return SDL_FALSE;
  3654     }
  3655     info->subsystem = SDL_SYSWM_UNKNOWN;
  3656 
  3657     if (!_this->GetWindowWMInfo) {
  3658         SDL_Unsupported();
  3659         return SDL_FALSE;
  3660     }
  3661     return (_this->GetWindowWMInfo(_this, window, info));
  3662 }
  3663 
  3664 void
  3665 SDL_StartTextInput(void)
  3666 {
  3667     SDL_Window *window;
  3668 
  3669     /* First, enable text events */
  3670     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3671     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3672 
  3673     /* Then show the on-screen keyboard, if any */
  3674     window = SDL_GetFocusWindow();
  3675     if (window && _this && _this->ShowScreenKeyboard) {
  3676         _this->ShowScreenKeyboard(_this, window);
  3677     }
  3678 
  3679     /* Finally start the text input system */
  3680     if (_this && _this->StartTextInput) {
  3681         _this->StartTextInput(_this);
  3682     }
  3683 }
  3684 
  3685 SDL_bool
  3686 SDL_IsTextInputActive(void)
  3687 {
  3688     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3689 }
  3690 
  3691 void
  3692 SDL_StopTextInput(void)
  3693 {
  3694     SDL_Window *window;
  3695 
  3696     /* Stop the text input system */
  3697     if (_this && _this->StopTextInput) {
  3698         _this->StopTextInput(_this);
  3699     }
  3700 
  3701     /* Hide the on-screen keyboard, if any */
  3702     window = SDL_GetFocusWindow();
  3703     if (window && _this && _this->HideScreenKeyboard) {
  3704         _this->HideScreenKeyboard(_this, window);
  3705     }
  3706 
  3707     /* Finally disable text events */
  3708     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3709     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3710 }
  3711 
  3712 void
  3713 SDL_SetTextInputRect(SDL_Rect *rect)
  3714 {
  3715     if (_this && _this->SetTextInputRect) {
  3716         _this->SetTextInputRect(_this, rect);
  3717     }
  3718 }
  3719 
  3720 SDL_bool
  3721 SDL_HasScreenKeyboardSupport(void)
  3722 {
  3723     if (_this && _this->HasScreenKeyboardSupport) {
  3724         return _this->HasScreenKeyboardSupport(_this);
  3725     }
  3726     return SDL_FALSE;
  3727 }
  3728 
  3729 SDL_bool
  3730 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3731 {
  3732     if (window && _this && _this->IsScreenKeyboardShown) {
  3733         return _this->IsScreenKeyboardShown(_this, window);
  3734     }
  3735     return SDL_FALSE;
  3736 }
  3737 
  3738 #if SDL_VIDEO_DRIVER_ANDROID
  3739 #include "android/SDL_androidmessagebox.h"
  3740 #endif
  3741 #if SDL_VIDEO_DRIVER_WINDOWS
  3742 #include "windows/SDL_windowsmessagebox.h"
  3743 #endif
  3744 #if SDL_VIDEO_DRIVER_WINRT
  3745 #include "winrt/SDL_winrtmessagebox.h"
  3746 #endif
  3747 #if SDL_VIDEO_DRIVER_COCOA
  3748 #include "cocoa/SDL_cocoamessagebox.h"
  3749 #endif
  3750 #if SDL_VIDEO_DRIVER_UIKIT
  3751 #include "uikit/SDL_uikitmessagebox.h"
  3752 #endif
  3753 #if SDL_VIDEO_DRIVER_X11
  3754 #include "x11/SDL_x11messagebox.h"
  3755 #endif
  3756 
  3757 
  3758 #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11
  3759 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3760 {
  3761     SDL_SysWMinfo info;
  3762     SDL_Window *window = messageboxdata->window;
  3763 
  3764     if (!window) {
  3765         return SDL_TRUE;
  3766     }
  3767 
  3768     SDL_VERSION(&info.version);
  3769     if (!SDL_GetWindowWMInfo(window, &info)) {
  3770         return SDL_TRUE;
  3771     } else {
  3772         return (info.subsystem == drivertype);
  3773     }
  3774 }
  3775 #endif
  3776 
  3777 int
  3778 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3779 {
  3780     int dummybutton;
  3781     int retval = -1;
  3782     SDL_bool relative_mode;
  3783     int show_cursor_prev;
  3784     SDL_bool mouse_captured;
  3785     SDL_Window *current_window;
  3786 
  3787     if (!messageboxdata) {
  3788         return SDL_InvalidParamError("messageboxdata");
  3789     } else if (messageboxdata->numbuttons < 0) {
  3790         return SDL_SetError("Invalid number of buttons");
  3791     }
  3792 
  3793     current_window = SDL_GetKeyboardFocus();
  3794     mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
  3795     relative_mode = SDL_GetRelativeMouseMode();
  3796     SDL_CaptureMouse(SDL_FALSE);
  3797     SDL_SetRelativeMouseMode(SDL_FALSE);
  3798     show_cursor_prev = SDL_ShowCursor(1);
  3799     SDL_ResetKeyboard();
  3800 
  3801     if (!buttonid) {
  3802         buttonid = &dummybutton;
  3803     }
  3804 
  3805     if (_this && _this->ShowMessageBox) {
  3806         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3807     }
  3808 
  3809     /* It's completely fine to call this function before video is initialized */
  3810 #if SDL_VIDEO_DRIVER_ANDROID
  3811     if (retval == -1 &&
  3812         Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3813         retval = 0;
  3814     }
  3815 #endif
  3816 #if SDL_VIDEO_DRIVER_WINDOWS
  3817     if (retval == -1 &&
  3818         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3819         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3820         retval = 0;
  3821     }
  3822 #endif
  3823 #if SDL_VIDEO_DRIVER_WINRT
  3824     if (retval == -1 &&
  3825         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
  3826         WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3827         retval = 0;
  3828     }
  3829 #endif
  3830 #if SDL_VIDEO_DRIVER_COCOA
  3831     if (retval == -1 &&
  3832         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3833         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3834         retval = 0;
  3835     }
  3836 #endif
  3837 #if SDL_VIDEO_DRIVER_UIKIT
  3838     if (retval == -1 &&
  3839         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3840         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3841         retval = 0;
  3842     }
  3843 #endif
  3844 #if SDL_VIDEO_DRIVER_X11
  3845     if (retval == -1 &&
  3846         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3847         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3848         retval = 0;
  3849     }
  3850 #endif
  3851     if (retval == -1) {
  3852         SDL_SetError("No message system available");
  3853     }
  3854 
  3855     if (current_window) {
  3856         SDL_RaiseWindow(current_window);
  3857         if (mouse_captured) {
  3858             SDL_CaptureMouse(SDL_TRUE);
  3859         }
  3860     }
  3861 
  3862     SDL_ShowCursor(show_cursor_prev);
  3863     SDL_SetRelativeMouseMode(relative_mode);
  3864 
  3865     return retval;
  3866 }
  3867 
  3868 int
  3869 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3870 {
  3871 #ifdef __EMSCRIPTEN__
  3872     /* !!! FIXME: propose a browser API for this, get this #ifdef out of here? */
  3873     /* Web browsers don't (currently) have an API for a custom message box
  3874        that can block, but for the most common case (SDL_ShowSimpleMessageBox),
  3875        we can use the standard Javascript alert() function. */
  3876     EM_ASM_({
  3877         alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1));
  3878     }, title, message);
  3879     return 0;
  3880 #else
  3881     SDL_MessageBoxData data;
  3882     SDL_MessageBoxButtonData button;
  3883 
  3884     SDL_zero(data);
  3885     data.flags = flags;
  3886     data.title = title;
  3887     data.message = message;
  3888     data.numbuttons = 1;
  3889     data.buttons = &button;
  3890     data.window = window;
  3891 
  3892     SDL_zero(button);
  3893     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3894     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3895     button.text = "OK";
  3896 
  3897     return SDL_ShowMessageBox(&data, NULL);
  3898 #endif
  3899 }
  3900 
  3901 SDL_bool
  3902 SDL_ShouldAllowTopmost(void)
  3903 {
  3904     return SDL_GetHintBoolean(SDL_HINT_ALLOW_TOPMOST, SDL_TRUE);
  3905 }
  3906 
  3907 int
  3908 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
  3909 {
  3910     CHECK_WINDOW_MAGIC(window, -1);
  3911 
  3912     if (!_this->SetWindowHitTest) {
  3913         return SDL_Unsupported();
  3914     } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
  3915         return -1;
  3916     }
  3917 
  3918     window->hit_test = callback;
  3919     window->hit_test_data = userdata;
  3920 
  3921     return 0;
  3922 }
  3923 
  3924 float
  3925 SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
  3926 {
  3927     float den2 = hinches * hinches + vinches * vinches;
  3928     if (den2 <= 0.0f) {
  3929         return 0.0f;
  3930     }
  3931 
  3932     return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
  3933                    SDL_sqrt((double)den2));
  3934 }
  3935 
  3936 /*
  3937  * Functions used by iOS application delegates
  3938  */
  3939 void SDL_OnApplicationWillTerminate(void)
  3940 {
  3941     SDL_SendAppEvent(SDL_APP_TERMINATING);
  3942 }
  3943 
  3944 void SDL_OnApplicationDidReceiveMemoryWarning(void)
  3945 {
  3946     SDL_SendAppEvent(SDL_APP_LOWMEMORY);
  3947 }
  3948 
  3949 void SDL_OnApplicationWillResignActive(void)
  3950 {
  3951     if (_this) {
  3952         SDL_Window *window;
  3953         for (window = _this->windows; window != NULL; window = window->next) {
  3954             SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
  3955             SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
  3956         }
  3957     }
  3958     SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
  3959 }
  3960 
  3961 void SDL_OnApplicationDidEnterBackground(void)
  3962 {
  3963     SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
  3964 }
  3965 
  3966 void SDL_OnApplicationWillEnterForeground(void)
  3967 {
  3968     SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
  3969 }
  3970 
  3971 void SDL_OnApplicationDidBecomeActive(void)
  3972 {
  3973     SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
  3974 
  3975     if (_this) {
  3976         SDL_Window *window;
  3977         for (window = _this->windows; window != NULL; window = window->next) {
  3978             SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
  3979             SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  3980         }
  3981     }
  3982 }
  3983 
  3984 #define NOT_A_VULKAN_WINDOW "The specified window isn't a Vulkan window"
  3985 
  3986 int SDL_Vulkan_LoadLibrary(const char *path)
  3987 {
  3988     int retval;
  3989     if (!_this) {
  3990         SDL_UninitializedVideo();
  3991         return -1;
  3992     }
  3993     if (_this->vulkan_config.loader_loaded) {
  3994         if (path && SDL_strcmp(path, _this->vulkan_config.loader_path) != 0) {
  3995             return SDL_SetError("Vulkan loader library already loaded");
  3996         }
  3997         retval = 0;
  3998     } else {
  3999         if (!_this->Vulkan_LoadLibrary) {
  4000             return SDL_SetError("Vulkan support is either not configured in SDL "
  4001                                 "or not available in current SDL video driver "
  4002                                 "(%s) or platform", _this->name);
  4003         }
  4004         retval = _this->Vulkan_LoadLibrary(_this, path);
  4005     }
  4006     if (retval == 0) {
  4007         _this->vulkan_config.loader_loaded++;
  4008     }
  4009     return retval;
  4010 }
  4011 
  4012 void *SDL_Vulkan_GetVkGetInstanceProcAddr(void)
  4013 {
  4014     if (!_this) {
  4015         SDL_UninitializedVideo();
  4016         return NULL;
  4017     }
  4018     if (!_this->vulkan_config.loader_loaded) {
  4019         SDL_SetError("No Vulkan loader has been loaded");
  4020         return NULL;
  4021     }
  4022     return _this->vulkan_config.vkGetInstanceProcAddr;
  4023 }
  4024 
  4025 void SDL_Vulkan_UnloadLibrary(void)
  4026 {
  4027     if (!_this) {
  4028         SDL_UninitializedVideo();
  4029         return;
  4030     }
  4031     if (_this->vulkan_config.loader_loaded > 0) {
  4032         if (--_this->vulkan_config.loader_loaded > 0) {
  4033             return;
  4034         }
  4035         if (_this->Vulkan_UnloadLibrary) {
  4036             _this->Vulkan_UnloadLibrary(_this);
  4037         }
  4038     }
  4039 }
  4040 
  4041 SDL_bool SDL_Vulkan_GetInstanceExtensions(SDL_Window *window, unsigned *count, const char **names)
  4042 {
  4043     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  4044 
  4045     if (!(window->flags & SDL_WINDOW_VULKAN)) {
  4046         SDL_SetError(NOT_A_VULKAN_WINDOW);
  4047         return SDL_FALSE;
  4048     }
  4049 
  4050     if (!count) {
  4051         SDL_InvalidParamError("count");
  4052         return SDL_FALSE;
  4053     }
  4054 
  4055     return _this->Vulkan_GetInstanceExtensions(_this, window, count, names);
  4056 }
  4057 
  4058 SDL_bool SDL_Vulkan_CreateSurface(SDL_Window *window,
  4059                                   VkInstance instance,
  4060                                   VkSurfaceKHR *surface)
  4061 {
  4062     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  4063 
  4064     if (!(window->flags & SDL_WINDOW_VULKAN)) {
  4065         SDL_SetError(NOT_A_VULKAN_WINDOW);
  4066         return SDL_FALSE;
  4067     }
  4068 
  4069     if (!instance) {
  4070         SDL_InvalidParamError("instance");
  4071         return SDL_FALSE;
  4072     }
  4073 
  4074     if (!surface) {
  4075         SDL_InvalidParamError("surface");
  4076         return SDL_FALSE;
  4077     }
  4078 
  4079     return _this->Vulkan_CreateSurface(_this, window, instance, surface);
  4080 }
  4081 
  4082 void SDL_Vulkan_GetDrawableSize(SDL_Window * window, int *w, int *h)
  4083 {
  4084     CHECK_WINDOW_MAGIC(window,);
  4085 
  4086     if (_this->Vulkan_GetDrawableSize) {
  4087         _this->Vulkan_GetDrawableSize(_this, window, w, h);
  4088     } else {
  4089         SDL_GetWindowSize(window, w, h);
  4090     }
  4091 }
  4092 
  4093 /* vi: set ts=4 sw=4 expandtab: */