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