src/video/SDL_video.c
author Ozkan Sezer <sezeroz@gmail.com>
Sat, 11 Jul 2020 08:10:02 +0300
changeset 13945 465afae5eb7e
parent 13932 22ef6c87d061
permissions -rw-r--r--
fix bug #5228 -- Add AltiVec detection for FreeBSD.

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