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