src/video/SDL_video.c
author EXL <exlmotodev@gmail.com>
Tue, 12 Nov 2019 17:24:37 -0500
changeset 13238 007002587d5d
parent 13230 57ed423da32a
child 13320 881796f84081
permissions -rw-r--r--
haiku: Rename BE_* entities to HAIKU_*
In favor Bugzilla #2349.
Update copyright years to 2019.

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