src/video/SDL_video.c
author Alex Szpakowski <slime73@gmail.com>
Thu, 15 Jan 2015 01:06:14 -0400
branchiOS-improvements
changeset 9532 318042c16b76
parent 9164 494876610c49
child 9533 e5693e855338
permissions -rw-r--r--
Several improvements to the iOS backend:

- Added new custom launch screen code. It uses the launch screen nib when available on iOS 8+, the launch images dictionary if the launch screen nib isn't available, and the old standard image names if the launch image dictionary isn't in the plist.
The launch screen is now hidden during the first call to SDL_PumpEvents rather than SDL_CreateWindow so apps can have the launch screen still visible if they do time-consuming loading after creating their window. It also fades out in roughly the same way as the system launch screen behavior.
It can be disabled by setting the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h to 0.

- A blank UIView is now created and displayed when the window is first created. The old behavior was to defer creating any view until SDL_GL_CreateContext, which prevented rotation, touch events, and other windowing-related things from working until then. This also makes it easier to use SDL_GetWindowWMInfo after creating a window.

- Moved the keyboard and animation callback code from SDL's UIView subclasses to its UIViewController subclass, which lets them work properly in all cases when a SDL window is valid, even before SDL_GL_CreateContext is called and after SDL_GL_DeleteContext is called.

- SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext are more robust.

- Fixed some edge cases where SDL windows weren't rotating properly or their reported sizes were out of sync with their actual sizes.

- Removed all calls to [UIApplication setStatusBarOrientation:]. It doesn't seem to work as expected in all cases in recent iOS versions.

- Some code style cleanup.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../SDL_internal.h"
    22 
    23 /* The high-level video driver subsystem */
    24 
    25 #include "SDL.h"
    26 #include "SDL_video.h"
    27 #include "SDL_sysvideo.h"
    28 #include "SDL_blit.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_rect_c.h"
    31 #include "../events/SDL_events_c.h"
    32 #include "../timer/SDL_timer_c.h"
    33 
    34 #include "SDL_syswm.h"
    35 
    36 #if SDL_VIDEO_OPENGL
    37 #include "SDL_opengl.h"
    38 #endif /* SDL_VIDEO_OPENGL */
    39 
    40 #if SDL_VIDEO_OPENGL_ES
    41 #include "SDL_opengles.h"
    42 #endif /* SDL_VIDEO_OPENGL_ES */
    43 
    44 /* GL and GLES2 headers conflict on Linux 32 bits */
    45 #if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL
    46 #include "SDL_opengles2.h"
    47 #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */
    48 
    49 /* On Windows, windows.h defines CreateWindow */
    50 #ifdef CreateWindow
    51 #undef CreateWindow
    52 #endif
    53 
    54 /* Available video drivers */
    55 static VideoBootStrap *bootstrap[] = {
    56 #if SDL_VIDEO_DRIVER_COCOA
    57     &COCOA_bootstrap,
    58 #endif
    59 #if SDL_VIDEO_DRIVER_X11
    60     &X11_bootstrap,
    61 #endif
    62 #if SDL_VIDEO_DRIVER_MIR
    63     &MIR_bootstrap,
    64 #endif
    65 #if SDL_VIDEO_DRIVER_WAYLAND
    66     &Wayland_bootstrap,
    67 #endif
    68 #if SDL_VIDEO_DRIVER_VIVANTE
    69     &VIVANTE_bootstrap,
    70 #endif
    71 #if SDL_VIDEO_DRIVER_DIRECTFB
    72     &DirectFB_bootstrap,
    73 #endif
    74 #if SDL_VIDEO_DRIVER_WINDOWS
    75     &WINDOWS_bootstrap,
    76 #endif
    77 #if SDL_VIDEO_DRIVER_WINRT
    78     &WINRT_bootstrap,
    79 #endif
    80 #if SDL_VIDEO_DRIVER_HAIKU
    81     &HAIKU_bootstrap,
    82 #endif
    83 #if SDL_VIDEO_DRIVER_PANDORA
    84     &PND_bootstrap,
    85 #endif
    86 #if SDL_VIDEO_DRIVER_UIKIT
    87     &UIKIT_bootstrap,
    88 #endif
    89 #if SDL_VIDEO_DRIVER_ANDROID
    90     &Android_bootstrap,
    91 #endif
    92 #if SDL_VIDEO_DRIVER_PSP
    93     &PSP_bootstrap,
    94 #endif
    95 #if SDL_VIDEO_DRIVER_RPI
    96     &RPI_bootstrap,
    97 #endif 
    98 #if SDL_VIDEO_DRIVER_NACL
    99     &NACL_bootstrap,
   100 #endif
   101 #if SDL_VIDEO_DRIVER_DUMMY
   102     &DUMMY_bootstrap,
   103 #endif
   104     NULL
   105 };
   106 
   107 static SDL_VideoDevice *_this = NULL;
   108 
   109 #define CHECK_WINDOW_MAGIC(window, retval) \
   110     if (!_this) { \
   111         SDL_UninitializedVideo(); \
   112         return retval; \
   113     } \
   114     if (!window || window->magic != &_this->window_magic) { \
   115         SDL_SetError("Invalid window"); \
   116         return retval; \
   117     }
   118 
   119 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
   120     if (!_this) { \
   121         SDL_UninitializedVideo(); \
   122         return retval; \
   123     } \
   124     SDL_assert(_this->displays != NULL); \
   125     if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
   126         SDL_SetError("displayIndex must be in the range 0 - %d", \
   127                      _this->num_displays - 1); \
   128         return retval; \
   129     }
   130 
   131 #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
   132 
   133 #ifdef __MACOSX__
   134 /* Support for Mac OS X fullscreen spaces */
   135 extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window);
   136 extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state);
   137 #endif
   138 
   139 
   140 /* Support for framebuffer emulation using an accelerated renderer */
   141 
   142 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
   143 
   144 typedef struct {
   145     SDL_Renderer *renderer;
   146     SDL_Texture *texture;
   147     void *pixels;
   148     int pitch;
   149     int bytes_per_pixel;
   150 } SDL_WindowTextureData;
   151 
   152 static SDL_bool
   153 ShouldUseTextureFramebuffer()
   154 {
   155     const char *hint;
   156 
   157     /* If there's no native framebuffer support then there's no option */
   158     if (!_this->CreateWindowFramebuffer) {
   159         return SDL_TRUE;
   160     }
   161 
   162     /* If the user has specified a software renderer we can't use a
   163        texture framebuffer, or renderer creation will go recursive.
   164      */
   165     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   166     if (hint && SDL_strcasecmp(hint, "software") == 0) {
   167         return SDL_FALSE;
   168     }
   169 
   170     /* See if the user or application wants a specific behavior */
   171     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   172     if (hint) {
   173         if (*hint == '0') {
   174             return SDL_FALSE;
   175         } else {
   176             return SDL_TRUE;
   177         }
   178     }
   179 
   180     /* Each platform has different performance characteristics */
   181 #if defined(__WIN32__)
   182     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
   183      */
   184     return SDL_FALSE;
   185 
   186 #elif defined(__MACOSX__)
   187     /* Mac OS X uses OpenGL as the native fast path */
   188     return SDL_TRUE;
   189 
   190 #elif defined(__LINUX__)
   191     /* Properly configured OpenGL drivers are faster than MIT-SHM */
   192 #if SDL_VIDEO_OPENGL
   193     /* Ugh, find a way to cache this value! */
   194     {
   195         SDL_Window *window;
   196         SDL_GLContext context;
   197         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
   198 
   199         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
   200         if (window) {
   201             context = SDL_GL_CreateContext(window);
   202             if (context) {
   203                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
   204                 const char *vendor = NULL;
   205 
   206                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
   207                 if (glGetStringFunc) {
   208                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
   209                 }
   210                 /* Add more vendors here at will... */
   211                 if (vendor &&
   212                     (SDL_strstr(vendor, "ATI Technologies") ||
   213                      SDL_strstr(vendor, "NVIDIA"))) {
   214                     hasAcceleratedOpenGL = SDL_TRUE;
   215                 }
   216                 SDL_GL_DeleteContext(context);
   217             }
   218             SDL_DestroyWindow(window);
   219         }
   220         return hasAcceleratedOpenGL;
   221     }
   222 #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   223     /* Let's be optimistic about this! */
   224     return SDL_TRUE;
   225 #else
   226     return SDL_FALSE;
   227 #endif
   228 
   229 #else
   230     /* Play it safe, assume that if there is a framebuffer driver that it's
   231        optimized for the current platform.
   232     */
   233     return SDL_FALSE;
   234 #endif
   235 }
   236 
   237 static int
   238 SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
   239 {
   240     SDL_WindowTextureData *data;
   241 
   242     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   243     if (!data) {
   244         SDL_Renderer *renderer = NULL;
   245         int i;
   246         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   247 
   248         /* Check to see if there's a specific driver requested */
   249         if (hint && *hint != '0' && *hint != '1' &&
   250             SDL_strcasecmp(hint, "software") != 0) {
   251             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   252                 SDL_RendererInfo info;
   253                 SDL_GetRenderDriverInfo(i, &info);
   254                 if (SDL_strcasecmp(info.name, hint) == 0) {
   255                     renderer = SDL_CreateRenderer(window, i, 0);
   256                     break;
   257                 }
   258             }
   259         }
   260         
   261         if (!renderer) {
   262             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   263                 SDL_RendererInfo info;
   264                 SDL_GetRenderDriverInfo(i, &info);
   265                 if (SDL_strcmp(info.name, "software") != 0) {
   266                     renderer = SDL_CreateRenderer(window, i, 0);
   267                     if (renderer) {
   268                         break;
   269                     }
   270                 }
   271             }
   272         }
   273         if (!renderer) {
   274             return SDL_SetError("No hardware accelerated renderers available");
   275         }
   276 
   277         /* Create the data after we successfully create the renderer (bug #1116) */
   278         data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
   279         if (!data) {
   280             SDL_DestroyRenderer(renderer);
   281             return SDL_OutOfMemory();
   282         }
   283         SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
   284 
   285         data->renderer = renderer;
   286     }
   287 
   288     /* Free any old texture and pixel data */
   289     if (data->texture) {
   290         SDL_DestroyTexture(data->texture);
   291         data->texture = NULL;
   292     }
   293     SDL_free(data->pixels);
   294     data->pixels = NULL;
   295 
   296     {
   297         SDL_RendererInfo info;
   298         Uint32 i;
   299 
   300         if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
   301             return -1;
   302         }
   303 
   304         /* Find the first format without an alpha channel */
   305         *format = info.texture_formats[0];
   306 
   307         for (i = 0; i < info.num_texture_formats; ++i) {
   308             if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
   309                     !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
   310                 *format = info.texture_formats[i];
   311                 break;
   312             }
   313         }
   314     }
   315 
   316     data->texture = SDL_CreateTexture(data->renderer, *format,
   317                                       SDL_TEXTUREACCESS_STREAMING,
   318                                       window->w, window->h);
   319     if (!data->texture) {
   320         return -1;
   321     }
   322 
   323     /* Create framebuffer data */
   324     data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
   325     data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
   326     data->pixels = SDL_malloc(window->h * data->pitch);
   327     if (!data->pixels) {
   328         return SDL_OutOfMemory();
   329     }
   330 
   331     *pixels = data->pixels;
   332     *pitch = data->pitch;
   333 
   334     /* Make sure we're not double-scaling the viewport */
   335     SDL_RenderSetViewport(data->renderer, NULL);
   336 
   337     return 0;
   338 }
   339 
   340 static int
   341 SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects)
   342 {
   343     SDL_WindowTextureData *data;
   344     SDL_Rect rect;
   345     void *src;
   346 
   347     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   348     if (!data || !data->texture) {
   349         return SDL_SetError("No window texture data");
   350     }
   351 
   352     /* Update a single rect that contains subrects for best DMA performance */
   353     if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
   354         src = (void *)((Uint8 *)data->pixels +
   355                         rect.y * data->pitch +
   356                         rect.x * data->bytes_per_pixel);
   357         if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
   358             return -1;
   359         }
   360 
   361         if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
   362             return -1;
   363         }
   364 
   365         SDL_RenderPresent(data->renderer);
   366     }
   367     return 0;
   368 }
   369 
   370 static void
   371 SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window)
   372 {
   373     SDL_WindowTextureData *data;
   374 
   375     data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
   376     if (!data) {
   377         return;
   378     }
   379     if (data->texture) {
   380         SDL_DestroyTexture(data->texture);
   381     }
   382     if (data->renderer) {
   383         SDL_DestroyRenderer(data->renderer);
   384     }
   385     SDL_free(data->pixels);
   386     SDL_free(data);
   387 }
   388 
   389 
   390 static int
   391 cmpmodes(const void *A, const void *B)
   392 {
   393     const SDL_DisplayMode *a = (const SDL_DisplayMode *) A;
   394     const SDL_DisplayMode *b = (const SDL_DisplayMode *) B;
   395     if (a == b) {
   396         return 0;
   397     } else if (a->w != b->w) {
   398         return b->w - a->w;
   399     } else if (a->h != b->h) {
   400         return b->h - a->h;
   401     } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) {
   402         return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format);
   403     } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) {
   404         return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format);
   405     } else if (a->refresh_rate != b->refresh_rate) {
   406         return b->refresh_rate - a->refresh_rate;
   407     }
   408     return 0;
   409 }
   410 
   411 static int
   412 SDL_UninitializedVideo()
   413 {
   414     return SDL_SetError("Video subsystem has not been initialized");
   415 }
   416 
   417 int
   418 SDL_GetNumVideoDrivers(void)
   419 {
   420     return SDL_arraysize(bootstrap) - 1;
   421 }
   422 
   423 const char *
   424 SDL_GetVideoDriver(int index)
   425 {
   426     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   427         return bootstrap[index]->name;
   428     }
   429     return NULL;
   430 }
   431 
   432 /*
   433  * Initialize the video and event subsystems -- determine native pixel format
   434  */
   435 int
   436 SDL_VideoInit(const char *driver_name)
   437 {
   438     SDL_VideoDevice *video;
   439     const char *hint;
   440     int index;
   441     int i;
   442     SDL_bool allow_screensaver;
   443 
   444     /* Check to make sure we don't overwrite '_this' */
   445     if (_this != NULL) {
   446         SDL_VideoQuit();
   447     }
   448 
   449 #if !SDL_TIMERS_DISABLED
   450     SDL_TicksInit();
   451 #endif
   452 
   453     /* Start the event loop */
   454     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||
   455         SDL_KeyboardInit() < 0 ||
   456         SDL_MouseInit() < 0 ||
   457         SDL_TouchInit() < 0) {
   458         return -1;
   459     }
   460 
   461     /* Select the proper video driver */
   462     index = 0;
   463     video = NULL;
   464     if (driver_name == NULL) {
   465         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   466     }
   467     if (driver_name != NULL) {
   468         for (i = 0; bootstrap[i]; ++i) {
   469             if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {
   470                 if (bootstrap[i]->available()) {
   471                     video = bootstrap[i]->create(index);
   472                     break;
   473                 }
   474             }
   475         }
   476     } else {
   477         for (i = 0; bootstrap[i]; ++i) {
   478             if (bootstrap[i]->available()) {
   479                 video = bootstrap[i]->create(index);
   480                 if (video != NULL) {
   481                     break;
   482                 }
   483             }
   484         }
   485     }
   486     if (video == NULL) {
   487         if (driver_name) {
   488             return SDL_SetError("%s not available", driver_name);
   489         }
   490         return SDL_SetError("No available video device");
   491     }
   492     _this = video;
   493     _this->name = bootstrap[i]->name;
   494     _this->next_object_id = 1;
   495 
   496 
   497     /* Set some very sane GL defaults */
   498     _this->gl_config.driver_loaded = 0;
   499     _this->gl_config.dll_handle = NULL;
   500     SDL_GL_ResetAttributes();
   501 
   502     _this->current_glwin_tls = SDL_TLSCreate();
   503     _this->current_glctx_tls = SDL_TLSCreate();
   504 
   505     /* Initialize the video subsystem */
   506     if (_this->VideoInit(_this) < 0) {
   507         SDL_VideoQuit();
   508         return -1;
   509     }
   510 
   511     /* Make sure some displays were added */
   512     if (_this->num_displays == 0) {
   513         SDL_VideoQuit();
   514         return SDL_SetError("The video driver did not add any displays");
   515     }
   516 
   517     /* Add the renderer framebuffer emulation if desired */
   518     if (ShouldUseTextureFramebuffer()) {
   519         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
   520         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
   521         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
   522     }
   523 
   524     /* Disable the screen saver by default. This is a change from <= 2.0.1,
   525        but most things using SDL are games or media players; you wouldn't
   526        want a screensaver to trigger if you're playing exclusively with a
   527        joystick, or passively watching a movie. Things that use SDL but
   528        function more like a normal desktop app should explicitly reenable the
   529        screensaver. */
   530     hint = SDL_GetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER);
   531     if (hint) {
   532         allow_screensaver = SDL_atoi(hint) ? SDL_TRUE : SDL_FALSE;
   533     } else {
   534         allow_screensaver = SDL_FALSE;
   535     }
   536     if (!allow_screensaver) {
   537         SDL_DisableScreenSaver();
   538     }
   539 
   540     /* If we don't use a screen keyboard, turn on text input by default,
   541        otherwise programs that expect to get text events without enabling
   542        UNICODE input won't get any events.
   543 
   544        Actually, come to think of it, you needed to call SDL_EnableUNICODE(1)
   545        in SDL 1.2 before you got text input events.  Hmm...
   546      */
   547     if (!SDL_HasScreenKeyboardSupport()) {
   548         SDL_StartTextInput();
   549     }
   550 
   551     /* We're ready to go! */
   552     return 0;
   553 }
   554 
   555 const char *
   556 SDL_GetCurrentVideoDriver()
   557 {
   558     if (!_this) {
   559         SDL_UninitializedVideo();
   560         return NULL;
   561     }
   562     return _this->name;
   563 }
   564 
   565 SDL_VideoDevice *
   566 SDL_GetVideoDevice(void)
   567 {
   568     return _this;
   569 }
   570 
   571 int
   572 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   573 {
   574     SDL_VideoDisplay display;
   575 
   576     SDL_zero(display);
   577     if (desktop_mode) {
   578         display.desktop_mode = *desktop_mode;
   579     }
   580     display.current_mode = display.desktop_mode;
   581 
   582     return SDL_AddVideoDisplay(&display);
   583 }
   584 
   585 int
   586 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   587 {
   588     SDL_VideoDisplay *displays;
   589     int index = -1;
   590 
   591     displays =
   592         SDL_realloc(_this->displays,
   593                     (_this->num_displays + 1) * sizeof(*displays));
   594     if (displays) {
   595         index = _this->num_displays++;
   596         displays[index] = *display;
   597         displays[index].device = _this;
   598         _this->displays = displays;
   599 
   600         if (display->name) {
   601             displays[index].name = SDL_strdup(display->name);
   602         } else {
   603             char name[32];
   604 
   605             SDL_itoa(index, name, 10);
   606             displays[index].name = SDL_strdup(name);
   607         }
   608     } else {
   609         SDL_OutOfMemory();
   610     }
   611     return index;
   612 }
   613 
   614 int
   615 SDL_GetNumVideoDisplays(void)
   616 {
   617     if (!_this) {
   618         SDL_UninitializedVideo();
   619         return 0;
   620     }
   621     return _this->num_displays;
   622 }
   623 
   624 static int
   625 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   626 {
   627     int displayIndex;
   628 
   629     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   630         if (display == &_this->displays[displayIndex]) {
   631             return displayIndex;
   632         }
   633     }
   634 
   635     /* Couldn't find the display, just use index 0 */
   636     return 0;
   637 }
   638 
   639 void *
   640 SDL_GetDisplayDriverData(int displayIndex)
   641 {
   642     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   643 
   644     return _this->displays[displayIndex].driverdata;
   645 }
   646 
   647 const char *
   648 SDL_GetDisplayName(int displayIndex)
   649 {
   650     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   651 
   652     return _this->displays[displayIndex].name;
   653 }
   654 
   655 int
   656 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   657 {
   658     CHECK_DISPLAY_INDEX(displayIndex, -1);
   659 
   660     if (rect) {
   661         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   662 
   663         if (_this->GetDisplayBounds) {
   664             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   665                 return 0;
   666             }
   667         }
   668 
   669         /* Assume that the displays are left to right */
   670         if (displayIndex == 0) {
   671             rect->x = 0;
   672             rect->y = 0;
   673         } else {
   674             SDL_GetDisplayBounds(displayIndex-1, rect);
   675             rect->x += rect->w;
   676         }
   677         rect->w = display->current_mode.w;
   678         rect->h = display->current_mode.h;
   679     }
   680     return 0;
   681 }
   682 
   683 SDL_bool
   684 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   685 {
   686     SDL_DisplayMode *modes;
   687     int i, nmodes;
   688 
   689     /* Make sure we don't already have the mode in the list */
   690     modes = display->display_modes;
   691     nmodes = display->num_display_modes;
   692     for (i = 0; i < nmodes; ++i) {
   693         if (cmpmodes(mode, &modes[i]) == 0) {
   694             return SDL_FALSE;
   695         }
   696     }
   697 
   698     /* Go ahead and add the new mode */
   699     if (nmodes == display->max_display_modes) {
   700         modes =
   701             SDL_realloc(modes,
   702                         (display->max_display_modes + 32) * sizeof(*modes));
   703         if (!modes) {
   704             return SDL_FALSE;
   705         }
   706         display->display_modes = modes;
   707         display->max_display_modes += 32;
   708     }
   709     modes[nmodes] = *mode;
   710     display->num_display_modes++;
   711 
   712     /* Re-sort video modes */
   713     SDL_qsort(display->display_modes, display->num_display_modes,
   714               sizeof(SDL_DisplayMode), cmpmodes);
   715 
   716     return SDL_TRUE;
   717 }
   718 
   719 static int
   720 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   721 {
   722     if (!display->num_display_modes && _this->GetDisplayModes) {
   723         _this->GetDisplayModes(_this, display);
   724         SDL_qsort(display->display_modes, display->num_display_modes,
   725                   sizeof(SDL_DisplayMode), cmpmodes);
   726     }
   727     return display->num_display_modes;
   728 }
   729 
   730 int
   731 SDL_GetNumDisplayModes(int displayIndex)
   732 {
   733     CHECK_DISPLAY_INDEX(displayIndex, -1);
   734 
   735     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   736 }
   737 
   738 int
   739 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   740 {
   741     SDL_VideoDisplay *display;
   742 
   743     CHECK_DISPLAY_INDEX(displayIndex, -1);
   744 
   745     display = &_this->displays[displayIndex];
   746     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   747         return SDL_SetError("index must be in the range of 0 - %d",
   748                             SDL_GetNumDisplayModesForDisplay(display) - 1);
   749     }
   750     if (mode) {
   751         *mode = display->display_modes[index];
   752     }
   753     return 0;
   754 }
   755 
   756 int
   757 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   758 {
   759     SDL_VideoDisplay *display;
   760 
   761     CHECK_DISPLAY_INDEX(displayIndex, -1);
   762 
   763     display = &_this->displays[displayIndex];
   764     if (mode) {
   765         *mode = display->desktop_mode;
   766     }
   767     return 0;
   768 }
   769 
   770 int
   771 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   772 {
   773     SDL_VideoDisplay *display;
   774 
   775     CHECK_DISPLAY_INDEX(displayIndex, -1);
   776 
   777     display = &_this->displays[displayIndex];
   778     if (mode) {
   779         *mode = display->current_mode;
   780     }
   781     return 0;
   782 }
   783 
   784 static SDL_DisplayMode *
   785 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   786                                     const SDL_DisplayMode * mode,
   787                                     SDL_DisplayMode * closest)
   788 {
   789     Uint32 target_format;
   790     int target_refresh_rate;
   791     int i;
   792     SDL_DisplayMode *current, *match;
   793 
   794     if (!mode || !closest) {
   795         SDL_SetError("Missing desired mode or closest mode parameter");
   796         return NULL;
   797     }
   798 
   799     /* Default to the desktop format */
   800     if (mode->format) {
   801         target_format = mode->format;
   802     } else {
   803         target_format = display->desktop_mode.format;
   804     }
   805 
   806     /* Default to the desktop refresh rate */
   807     if (mode->refresh_rate) {
   808         target_refresh_rate = mode->refresh_rate;
   809     } else {
   810         target_refresh_rate = display->desktop_mode.refresh_rate;
   811     }
   812 
   813     match = NULL;
   814     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   815         current = &display->display_modes[i];
   816 
   817         if (current->w && (current->w < mode->w)) {
   818             /* Out of sorted modes large enough here */
   819             break;
   820         }
   821         if (current->h && (current->h < mode->h)) {
   822             if (current->w && (current->w == mode->w)) {
   823                 /* Out of sorted modes large enough here */
   824                 break;
   825             }
   826             /* Wider, but not tall enough, due to a different
   827                aspect ratio. This mode must be skipped, but closer
   828                modes may still follow. */
   829             continue;
   830         }
   831         if (!match || current->w < match->w || current->h < match->h) {
   832             match = current;
   833             continue;
   834         }
   835         if (current->format != match->format) {
   836             /* Sorted highest depth to lowest */
   837             if (current->format == target_format ||
   838                 (SDL_BITSPERPIXEL(current->format) >=
   839                  SDL_BITSPERPIXEL(target_format)
   840                  && SDL_PIXELTYPE(current->format) ==
   841                  SDL_PIXELTYPE(target_format))) {
   842                 match = current;
   843             }
   844             continue;
   845         }
   846         if (current->refresh_rate != match->refresh_rate) {
   847             /* Sorted highest refresh to lowest */
   848             if (current->refresh_rate >= target_refresh_rate) {
   849                 match = current;
   850             }
   851         }
   852     }
   853     if (match) {
   854         if (match->format) {
   855             closest->format = match->format;
   856         } else {
   857             closest->format = mode->format;
   858         }
   859         if (match->w && match->h) {
   860             closest->w = match->w;
   861             closest->h = match->h;
   862         } else {
   863             closest->w = mode->w;
   864             closest->h = mode->h;
   865         }
   866         if (match->refresh_rate) {
   867             closest->refresh_rate = match->refresh_rate;
   868         } else {
   869             closest->refresh_rate = mode->refresh_rate;
   870         }
   871         closest->driverdata = match->driverdata;
   872 
   873         /*
   874          * Pick some reasonable defaults if the app and driver don't
   875          * care
   876          */
   877         if (!closest->format) {
   878             closest->format = SDL_PIXELFORMAT_RGB888;
   879         }
   880         if (!closest->w) {
   881             closest->w = 640;
   882         }
   883         if (!closest->h) {
   884             closest->h = 480;
   885         }
   886         return closest;
   887     }
   888     return NULL;
   889 }
   890 
   891 SDL_DisplayMode *
   892 SDL_GetClosestDisplayMode(int displayIndex,
   893                           const SDL_DisplayMode * mode,
   894                           SDL_DisplayMode * closest)
   895 {
   896     SDL_VideoDisplay *display;
   897 
   898     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   899 
   900     display = &_this->displays[displayIndex];
   901     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   902 }
   903 
   904 static int
   905 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   906 {
   907     SDL_DisplayMode display_mode;
   908     SDL_DisplayMode current_mode;
   909 
   910     if (mode) {
   911         display_mode = *mode;
   912 
   913         /* Default to the current mode */
   914         if (!display_mode.format) {
   915             display_mode.format = display->current_mode.format;
   916         }
   917         if (!display_mode.w) {
   918             display_mode.w = display->current_mode.w;
   919         }
   920         if (!display_mode.h) {
   921             display_mode.h = display->current_mode.h;
   922         }
   923         if (!display_mode.refresh_rate) {
   924             display_mode.refresh_rate = display->current_mode.refresh_rate;
   925         }
   926 
   927         /* Get a good video mode, the closest one possible */
   928         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   929             return SDL_SetError("No video mode large enough for %dx%d",
   930                                 display_mode.w, display_mode.h);
   931         }
   932     } else {
   933         display_mode = display->desktop_mode;
   934     }
   935 
   936     /* See if there's anything left to do */
   937     current_mode = display->current_mode;
   938     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   939         return 0;
   940     }
   941 
   942     /* Actually change the display mode */
   943     if (!_this->SetDisplayMode) {
   944         return SDL_SetError("Video driver doesn't support changing display mode");
   945     }
   946     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   947         return -1;
   948     }
   949     display->current_mode = display_mode;
   950     return 0;
   951 }
   952 
   953 int
   954 SDL_GetWindowDisplayIndex(SDL_Window * window)
   955 {
   956     int displayIndex;
   957     int i, dist;
   958     int closest = -1;
   959     int closest_dist = 0x7FFFFFFF;
   960     SDL_Point center;
   961     SDL_Point delta;
   962     SDL_Rect rect;
   963 
   964     CHECK_WINDOW_MAGIC(window, -1);
   965 
   966     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   967         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   968         displayIndex = (window->x & 0xFFFF);
   969         if (displayIndex >= _this->num_displays) {
   970             displayIndex = 0;
   971         }
   972         return displayIndex;
   973     }
   974     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   975         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   976         displayIndex = (window->y & 0xFFFF);
   977         if (displayIndex >= _this->num_displays) {
   978             displayIndex = 0;
   979         }
   980         return displayIndex;
   981     }
   982 
   983     /* Find the display containing the window */
   984     for (i = 0; i < _this->num_displays; ++i) {
   985         SDL_VideoDisplay *display = &_this->displays[i];
   986 
   987         if (display->fullscreen_window == window) {
   988             return i;
   989         }
   990     }
   991     center.x = window->x + window->w / 2;
   992     center.y = window->y + window->h / 2;
   993     for (i = 0; i < _this->num_displays; ++i) {
   994         SDL_GetDisplayBounds(i, &rect);
   995         if (SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   996             return i;
   997         }
   998 
   999         delta.x = center.x - (rect.x + rect.w / 2);
  1000         delta.y = center.y - (rect.y + rect.h / 2);
  1001         dist = (delta.x*delta.x + delta.y*delta.y);
  1002         if (dist < closest_dist) {
  1003             closest = i;
  1004             closest_dist = dist;
  1005         }
  1006     }
  1007     if (closest < 0) {
  1008         SDL_SetError("Couldn't find any displays");
  1009     }
  1010     return closest;
  1011 }
  1012 
  1013 SDL_VideoDisplay *
  1014 SDL_GetDisplayForWindow(SDL_Window *window)
  1015 {
  1016     int displayIndex = SDL_GetWindowDisplayIndex(window);
  1017     if (displayIndex >= 0) {
  1018         return &_this->displays[displayIndex];
  1019     } else {
  1020         return NULL;
  1021     }
  1022 }
  1023 
  1024 int
  1025 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
  1026 {
  1027     CHECK_WINDOW_MAGIC(window, -1);
  1028 
  1029     if (mode) {
  1030         window->fullscreen_mode = *mode;
  1031     } else {
  1032         SDL_zero(window->fullscreen_mode);
  1033     }
  1034 
  1035     if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1036         SDL_DisplayMode fullscreen_mode;
  1037         if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
  1038             SDL_SetDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode);
  1039         }
  1040     }
  1041     return 0;
  1042 }
  1043 
  1044 int
  1045 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
  1046 {
  1047     SDL_DisplayMode fullscreen_mode;
  1048     SDL_VideoDisplay *display;
  1049 
  1050     CHECK_WINDOW_MAGIC(window, -1);
  1051 
  1052     if (!mode) {
  1053         return SDL_InvalidParamError("mode");
  1054     }
  1055 
  1056     fullscreen_mode = window->fullscreen_mode;
  1057     if (!fullscreen_mode.w) {
  1058         fullscreen_mode.w = window->windowed.w;
  1059     }
  1060     if (!fullscreen_mode.h) {
  1061         fullscreen_mode.h = window->windowed.h;
  1062     }
  1063 
  1064     display = SDL_GetDisplayForWindow(window);
  1065 
  1066     /* if in desktop size mode, just return the size of the desktop */
  1067     if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1068         fullscreen_mode = display->desktop_mode;
  1069     } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
  1070                                              &fullscreen_mode,
  1071                                              &fullscreen_mode)) {
  1072         return SDL_SetError("Couldn't find display mode match");
  1073     }
  1074 
  1075     if (mode) {
  1076         *mode = fullscreen_mode;
  1077     }
  1078     return 0;
  1079 }
  1080 
  1081 Uint32
  1082 SDL_GetWindowPixelFormat(SDL_Window * window)
  1083 {
  1084     SDL_VideoDisplay *display;
  1085 
  1086     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1087 
  1088     display = SDL_GetDisplayForWindow(window);
  1089     return display->current_mode.format;
  1090 }
  1091 
  1092 static void
  1093 SDL_RestoreMousePosition(SDL_Window *window)
  1094 {
  1095     int x, y;
  1096 
  1097     if (window == SDL_GetMouseFocus()) {
  1098         SDL_GetMouseState(&x, &y);
  1099         SDL_WarpMouseInWindow(window, x, y);
  1100     }
  1101 }
  1102 
  1103 static int
  1104 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1105 {
  1106     SDL_VideoDisplay *display;
  1107     SDL_Window *other;
  1108 
  1109     CHECK_WINDOW_MAGIC(window,-1);
  1110 
  1111     /* if we are in the process of hiding don't go back to fullscreen */
  1112     if ( window->is_hiding && fullscreen )
  1113         return 0;
  1114     
  1115 #ifdef __MACOSX__
  1116     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
  1117         window->last_fullscreen_flags = window->flags;
  1118         return 0;
  1119     }
  1120 #endif
  1121 
  1122     display = SDL_GetDisplayForWindow(window);
  1123 
  1124     if (fullscreen) {
  1125         /* Hide any other fullscreen windows */
  1126         if (display->fullscreen_window &&
  1127             display->fullscreen_window != window) {
  1128             SDL_MinimizeWindow(display->fullscreen_window);
  1129         }
  1130     }
  1131 
  1132     /* See if anything needs to be done now */
  1133     if ((display->fullscreen_window == window) == fullscreen) {
  1134         if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
  1135             return 0;
  1136         }
  1137     }
  1138 
  1139     /* See if there are any fullscreen windows */
  1140     for (other = _this->windows; other; other = other->next) {
  1141         SDL_bool setDisplayMode = SDL_FALSE;
  1142 
  1143         if (other == window) {
  1144             setDisplayMode = fullscreen;
  1145         } else if (FULLSCREEN_VISIBLE(other) &&
  1146                    SDL_GetDisplayForWindow(other) == display) {
  1147             setDisplayMode = SDL_TRUE;
  1148         }
  1149 
  1150         if (setDisplayMode) {
  1151             SDL_DisplayMode fullscreen_mode;
  1152 
  1153             SDL_zero(fullscreen_mode);
  1154 
  1155             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1156                 SDL_bool resized = SDL_TRUE;
  1157 
  1158                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1159                     resized = SDL_FALSE;
  1160                 }
  1161 
  1162                 /* only do the mode change if we want exclusive fullscreen */
  1163                 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1164                     if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
  1165                         return -1;
  1166                     }
  1167                 } else {
  1168                     if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
  1169                         return -1;
  1170                     }
  1171                 }
  1172 
  1173                 if (_this->SetWindowFullscreen) {
  1174                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1175                 }
  1176                 display->fullscreen_window = other;
  1177 
  1178                 /* Generate a mode change event here */
  1179                 if (resized) {
  1180                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1181                                         fullscreen_mode.w, fullscreen_mode.h);
  1182                 } else {
  1183                     SDL_OnWindowResized(other);
  1184                 }
  1185 
  1186                 SDL_RestoreMousePosition(other);
  1187 
  1188                 window->last_fullscreen_flags = window->flags;
  1189                 return 0;
  1190             }
  1191         }
  1192     }
  1193 
  1194     /* Nope, restore the desktop mode */
  1195     SDL_SetDisplayModeForDisplay(display, NULL);
  1196 
  1197     if (_this->SetWindowFullscreen) {
  1198         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1199     }
  1200     display->fullscreen_window = NULL;
  1201 
  1202     /* Generate a mode change event here */
  1203     SDL_OnWindowResized(window);
  1204 
  1205     /* Restore the cursor position */
  1206     SDL_RestoreMousePosition(window);
  1207 
  1208     window->last_fullscreen_flags = window->flags;
  1209     return 0;
  1210 }
  1211 
  1212 #define CREATE_FLAGS \
  1213     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
  1214 
  1215 static void
  1216 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1217 {
  1218     window->windowed.x = window->x;
  1219     window->windowed.y = window->y;
  1220     window->windowed.w = window->w;
  1221     window->windowed.h = window->h;
  1222 
  1223     if (flags & SDL_WINDOW_MAXIMIZED) {
  1224         SDL_MaximizeWindow(window);
  1225     }
  1226     if (flags & SDL_WINDOW_MINIMIZED) {
  1227         SDL_MinimizeWindow(window);
  1228     }
  1229     if (flags & SDL_WINDOW_FULLSCREEN) {
  1230         SDL_SetWindowFullscreen(window, flags);
  1231     }
  1232     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1233         SDL_SetWindowGrab(window, SDL_TRUE);
  1234     }
  1235     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1236         SDL_ShowWindow(window);
  1237     }
  1238 }
  1239 
  1240 SDL_Window *
  1241 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1242 {
  1243     SDL_Window *window;
  1244     const char *hint;
  1245 
  1246     if (!_this) {
  1247         /* Initialize the video system if needed */
  1248         if (SDL_VideoInit(NULL) < 0) {
  1249             return NULL;
  1250         }
  1251     }
  1252 
  1253     /* Some platforms can't create zero-sized windows */
  1254     if (w < 1) {
  1255         w = 1;
  1256     }
  1257     if (h < 1) {
  1258         h = 1;
  1259     }
  1260 
  1261     /* Some platforms have OpenGL enabled by default */
  1262 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
  1263     flags |= SDL_WINDOW_OPENGL;
  1264 #endif
  1265     if (flags & SDL_WINDOW_OPENGL) {
  1266         if (!_this->GL_CreateContext) {
  1267             SDL_SetError("No OpenGL support in video driver");
  1268             return NULL;
  1269         }
  1270         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1271             return NULL;
  1272         }
  1273     }
  1274 
  1275     /* Unless the user has specified the high-DPI disabling hint, respect the
  1276      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1277      */
  1278     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1279         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1280         if (hint && SDL_atoi(hint) > 0) {
  1281             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1282         }
  1283     }
  1284 
  1285     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1286     if (!window) {
  1287         SDL_OutOfMemory();
  1288         return NULL;
  1289     }
  1290     window->magic = &_this->window_magic;
  1291     window->id = _this->next_object_id++;
  1292     window->x = x;
  1293     window->y = y;
  1294     window->w = w;
  1295     window->h = h;
  1296     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1297         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1298         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1299         int displayIndex;
  1300         SDL_Rect bounds;
  1301 
  1302         displayIndex = SDL_GetIndexOfDisplay(display);
  1303         SDL_GetDisplayBounds(displayIndex, &bounds);
  1304         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1305             window->x = bounds.x + (bounds.w - w) / 2;
  1306         }
  1307         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1308             window->y = bounds.y + (bounds.h - h) / 2;
  1309         }
  1310     }
  1311     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1312     window->last_fullscreen_flags = window->flags;
  1313     window->brightness = 1.0f;
  1314     window->next = _this->windows;
  1315     window->is_destroying = SDL_FALSE;
  1316 
  1317     if (_this->windows) {
  1318         _this->windows->prev = window;
  1319     }
  1320     _this->windows = window;
  1321 
  1322     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1323         SDL_DestroyWindow(window);
  1324         return NULL;
  1325     }
  1326 
  1327     if (title) {
  1328         SDL_SetWindowTitle(window, title);
  1329     }
  1330     SDL_FinishWindowCreation(window, flags);
  1331 
  1332     /* If the window was created fullscreen, make sure the mode code matches */
  1333     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1334 
  1335     return window;
  1336 }
  1337 
  1338 SDL_Window *
  1339 SDL_CreateWindowFrom(const void *data)
  1340 {
  1341     SDL_Window *window;
  1342 
  1343     if (!_this) {
  1344         SDL_UninitializedVideo();
  1345         return NULL;
  1346     }
  1347     if (!_this->CreateWindowFrom) {
  1348         SDL_Unsupported();
  1349         return NULL;
  1350     }
  1351     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1352     if (!window) {
  1353         SDL_OutOfMemory();
  1354         return NULL;
  1355     }
  1356     window->magic = &_this->window_magic;
  1357     window->id = _this->next_object_id++;
  1358     window->flags = SDL_WINDOW_FOREIGN;
  1359     window->last_fullscreen_flags = window->flags;
  1360     window->is_destroying = SDL_FALSE;
  1361     window->brightness = 1.0f;
  1362     window->next = _this->windows;
  1363     if (_this->windows) {
  1364         _this->windows->prev = window;
  1365     }
  1366     _this->windows = window;
  1367 
  1368     if (_this->CreateWindowFrom(_this, window, data) < 0) {
  1369         SDL_DestroyWindow(window);
  1370         return NULL;
  1371     }
  1372     return window;
  1373 }
  1374 
  1375 int
  1376 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1377 {
  1378     char *title = window->title;
  1379     SDL_Surface *icon = window->icon;
  1380     SDL_bool loaded_opengl = SDL_FALSE;
  1381 
  1382     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1383         return SDL_SetError("No OpenGL support in video driver");
  1384     }
  1385 
  1386     if (window->flags & SDL_WINDOW_FOREIGN) {
  1387         /* Can't destroy and re-create foreign windows, hrm */
  1388         flags |= SDL_WINDOW_FOREIGN;
  1389     } else {
  1390         flags &= ~SDL_WINDOW_FOREIGN;
  1391     }
  1392 
  1393     /* Restore video mode, etc. */
  1394     SDL_HideWindow(window);
  1395 
  1396     /* Tear down the old native window */
  1397     if (window->surface) {
  1398         window->surface->flags &= ~SDL_DONTFREE;
  1399         SDL_FreeSurface(window->surface);
  1400     }
  1401     if (_this->DestroyWindowFramebuffer) {
  1402         _this->DestroyWindowFramebuffer(_this, window);
  1403     }
  1404     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1405         _this->DestroyWindow(_this, window);
  1406     }
  1407 
  1408     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1409         if (flags & SDL_WINDOW_OPENGL) {
  1410             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1411                 return -1;
  1412             }
  1413             loaded_opengl = SDL_TRUE;
  1414         } else {
  1415             SDL_GL_UnloadLibrary();
  1416         }
  1417     }
  1418 
  1419     window->title = NULL;
  1420     window->icon = NULL;
  1421     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1422     window->last_fullscreen_flags = window->flags;
  1423     window->is_destroying = SDL_FALSE;
  1424 
  1425     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1426         if (_this->CreateWindow(_this, window) < 0) {
  1427             if (loaded_opengl) {
  1428                 SDL_GL_UnloadLibrary();
  1429                 window->flags &= ~SDL_WINDOW_OPENGL;
  1430             }
  1431             return -1;
  1432         }
  1433     }
  1434     if (flags & SDL_WINDOW_FOREIGN) {
  1435         window->flags |= SDL_WINDOW_FOREIGN;
  1436     }
  1437 
  1438     if (title) {
  1439         SDL_SetWindowTitle(window, title);
  1440         SDL_free(title);
  1441     }
  1442     if (icon) {
  1443         SDL_SetWindowIcon(window, icon);
  1444         SDL_FreeSurface(icon);
  1445     }
  1446 
  1447     if (window->hit_test) {
  1448         _this->SetWindowHitTest(window, SDL_TRUE);
  1449     }
  1450 
  1451     SDL_FinishWindowCreation(window, flags);
  1452 
  1453     return 0;
  1454 }
  1455 
  1456 Uint32
  1457 SDL_GetWindowID(SDL_Window * window)
  1458 {
  1459     CHECK_WINDOW_MAGIC(window, 0);
  1460 
  1461     return window->id;
  1462 }
  1463 
  1464 SDL_Window *
  1465 SDL_GetWindowFromID(Uint32 id)
  1466 {
  1467     SDL_Window *window;
  1468 
  1469     if (!_this) {
  1470         return NULL;
  1471     }
  1472     for (window = _this->windows; window; window = window->next) {
  1473         if (window->id == id) {
  1474             return window;
  1475         }
  1476     }
  1477     return NULL;
  1478 }
  1479 
  1480 Uint32
  1481 SDL_GetWindowFlags(SDL_Window * window)
  1482 {
  1483     CHECK_WINDOW_MAGIC(window, 0);
  1484 
  1485     return window->flags;
  1486 }
  1487 
  1488 void
  1489 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1490 {
  1491     CHECK_WINDOW_MAGIC(window,);
  1492 
  1493     if (title == window->title) {
  1494         return;
  1495     }
  1496     SDL_free(window->title);
  1497     if (title && *title) {
  1498         window->title = SDL_strdup(title);
  1499     } else {
  1500         window->title = NULL;
  1501     }
  1502 
  1503     if (_this->SetWindowTitle) {
  1504         _this->SetWindowTitle(_this, window);
  1505     }
  1506 }
  1507 
  1508 const char *
  1509 SDL_GetWindowTitle(SDL_Window * window)
  1510 {
  1511     CHECK_WINDOW_MAGIC(window, "");
  1512 
  1513     return window->title ? window->title : "";
  1514 }
  1515 
  1516 void
  1517 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1518 {
  1519     CHECK_WINDOW_MAGIC(window,);
  1520 
  1521     if (!icon) {
  1522         return;
  1523     }
  1524 
  1525     SDL_FreeSurface(window->icon);
  1526 
  1527     /* Convert the icon into ARGB8888 */
  1528     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1529     if (!window->icon) {
  1530         return;
  1531     }
  1532 
  1533     if (_this->SetWindowIcon) {
  1534         _this->SetWindowIcon(_this, window, window->icon);
  1535     }
  1536 }
  1537 
  1538 void*
  1539 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1540 {
  1541     SDL_WindowUserData *prev, *data;
  1542 
  1543     CHECK_WINDOW_MAGIC(window, NULL);
  1544 
  1545     /* Input validation */
  1546     if (name == NULL || name[0] == '\0') {
  1547       SDL_InvalidParamError("name");
  1548       return NULL;
  1549     }
  1550 
  1551     /* See if the named data already exists */
  1552     prev = NULL;
  1553     for (data = window->data; data; prev = data, data = data->next) {
  1554         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1555             void *last_value = data->data;
  1556 
  1557             if (userdata) {
  1558                 /* Set the new value */
  1559                 data->data = userdata;
  1560             } else {
  1561                 /* Delete this value */
  1562                 if (prev) {
  1563                     prev->next = data->next;
  1564                 } else {
  1565                     window->data = data->next;
  1566                 }
  1567                 SDL_free(data->name);
  1568                 SDL_free(data);
  1569             }
  1570             return last_value;
  1571         }
  1572     }
  1573 
  1574     /* Add new data to the window */
  1575     if (userdata) {
  1576         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1577         data->name = SDL_strdup(name);
  1578         data->data = userdata;
  1579         data->next = window->data;
  1580         window->data = data;
  1581     }
  1582     return NULL;
  1583 }
  1584 
  1585 void *
  1586 SDL_GetWindowData(SDL_Window * window, const char *name)
  1587 {
  1588     SDL_WindowUserData *data;
  1589 
  1590     CHECK_WINDOW_MAGIC(window, NULL);
  1591 
  1592     /* Input validation */
  1593     if (name == NULL || name[0] == '\0') {
  1594       SDL_InvalidParamError("name");
  1595       return NULL;
  1596     }
  1597 
  1598     for (data = window->data; data; data = data->next) {
  1599         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1600             return data->data;
  1601         }
  1602     }
  1603     return NULL;
  1604 }
  1605 
  1606 void
  1607 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1608 {
  1609     CHECK_WINDOW_MAGIC(window,);
  1610 
  1611     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1612         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1613         int displayIndex;
  1614         SDL_Rect bounds;
  1615 
  1616         SDL_zero(bounds);
  1617 
  1618         displayIndex = SDL_GetIndexOfDisplay(display);
  1619         SDL_GetDisplayBounds(displayIndex, &bounds);
  1620         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1621             x = bounds.x + (bounds.w - window->w) / 2;
  1622         }
  1623         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1624             y = bounds.y + (bounds.h - window->h) / 2;
  1625         }
  1626     }
  1627 
  1628     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1629         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1630             window->windowed.x = x;
  1631         }
  1632         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1633             window->windowed.y = y;
  1634         }
  1635     } else {
  1636         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1637             window->x = x;
  1638         }
  1639         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1640             window->y = y;
  1641         }
  1642 
  1643         if (_this->SetWindowPosition) {
  1644             _this->SetWindowPosition(_this, window);
  1645         }
  1646         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1647     }
  1648 }
  1649 
  1650 void
  1651 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1652 {
  1653     CHECK_WINDOW_MAGIC(window,);
  1654 
  1655     /* Fullscreen windows are always at their display's origin */
  1656     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1657         if (x) {
  1658             *x = 0;
  1659         }
  1660         if (y) {
  1661             *y = 0;
  1662         }
  1663     } else {
  1664         if (x) {
  1665             *x = window->x;
  1666         }
  1667         if (y) {
  1668             *y = window->y;
  1669         }
  1670     }
  1671 }
  1672 
  1673 void
  1674 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1675 {
  1676     CHECK_WINDOW_MAGIC(window,);
  1677     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1678         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1679         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1680         if ((want != have) && (_this->SetWindowBordered)) {
  1681             if (want) {
  1682                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1683             } else {
  1684                 window->flags |= SDL_WINDOW_BORDERLESS;
  1685             }
  1686             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1687         }
  1688     }
  1689 }
  1690 
  1691 void
  1692 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1693 {
  1694     CHECK_WINDOW_MAGIC(window,);
  1695     if (w <= 0) {
  1696         SDL_InvalidParamError("w");
  1697         return;
  1698     }
  1699     if (h <= 0) {
  1700         SDL_InvalidParamError("h");
  1701         return;
  1702     }
  1703 
  1704     /* Make sure we don't exceed any window size limits */
  1705     if (window->min_w && w < window->min_w)
  1706     {
  1707         w = window->min_w;
  1708     }
  1709     if (window->max_w && w > window->max_w)
  1710     {
  1711         w = window->max_w;
  1712     }
  1713     if (window->min_h && h < window->min_h)
  1714     {
  1715         h = window->min_h;
  1716     }
  1717     if (window->max_h && h > window->max_h)
  1718     {
  1719         h = window->max_h;
  1720     }
  1721 
  1722     window->windowed.w = w;
  1723     window->windowed.h = h;
  1724 
  1725     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1726         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1727             window->last_fullscreen_flags = 0;
  1728             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1729         }
  1730     } else {
  1731         window->w = w;
  1732         window->h = h;
  1733         if (_this->SetWindowSize) {
  1734             _this->SetWindowSize(_this, window);
  1735         }
  1736         if (window->w == w && window->h == h) {
  1737             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1738             SDL_OnWindowResized(window);
  1739         }
  1740     }
  1741 }
  1742 
  1743 void
  1744 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1745 {
  1746     CHECK_WINDOW_MAGIC(window,);
  1747     if (w) {
  1748         *w = window->w;
  1749     }
  1750     if (h) {
  1751         *h = window->h;
  1752     }
  1753 }
  1754 
  1755 void
  1756 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1757 {
  1758     CHECK_WINDOW_MAGIC(window,);
  1759     if (min_w <= 0) {
  1760         SDL_InvalidParamError("min_w");
  1761         return;
  1762     }
  1763     if (min_h <= 0) {
  1764         SDL_InvalidParamError("min_h");
  1765         return;
  1766     }
  1767 
  1768     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1769         window->min_w = min_w;
  1770         window->min_h = min_h;
  1771         if (_this->SetWindowMinimumSize) {
  1772             _this->SetWindowMinimumSize(_this, window);
  1773         }
  1774         /* Ensure that window is not smaller than minimal size */
  1775         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1776     }
  1777 }
  1778 
  1779 void
  1780 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1781 {
  1782     CHECK_WINDOW_MAGIC(window,);
  1783     if (min_w) {
  1784         *min_w = window->min_w;
  1785     }
  1786     if (min_h) {
  1787         *min_h = window->min_h;
  1788     }
  1789 }
  1790 
  1791 void
  1792 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1793 {
  1794     CHECK_WINDOW_MAGIC(window,);
  1795     if (max_w <= 0) {
  1796         SDL_InvalidParamError("max_w");
  1797         return;
  1798     }
  1799     if (max_h <= 0) {
  1800         SDL_InvalidParamError("max_h");
  1801         return;
  1802     }
  1803 
  1804     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1805         window->max_w = max_w;
  1806         window->max_h = max_h;
  1807         if (_this->SetWindowMaximumSize) {
  1808             _this->SetWindowMaximumSize(_this, window);
  1809         }
  1810         /* Ensure that window is not larger than maximal size */
  1811         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1812     }
  1813 }
  1814 
  1815 void
  1816 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1817 {
  1818     CHECK_WINDOW_MAGIC(window,);
  1819     if (max_w) {
  1820         *max_w = window->max_w;
  1821     }
  1822     if (max_h) {
  1823         *max_h = window->max_h;
  1824     }
  1825 }
  1826 
  1827 void
  1828 SDL_ShowWindow(SDL_Window * window)
  1829 {
  1830     CHECK_WINDOW_MAGIC(window,);
  1831 
  1832     if (window->flags & SDL_WINDOW_SHOWN) {
  1833         return;
  1834     }
  1835 
  1836     if (_this->ShowWindow) {
  1837         _this->ShowWindow(_this, window);
  1838     }
  1839     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1840 }
  1841 
  1842 void
  1843 SDL_HideWindow(SDL_Window * window)
  1844 {
  1845     CHECK_WINDOW_MAGIC(window,);
  1846 
  1847     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1848         return;
  1849     }
  1850 
  1851 	window->is_hiding = SDL_TRUE;
  1852     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1853 
  1854     if (_this->HideWindow) {
  1855         _this->HideWindow(_this, window);
  1856     }
  1857 	window->is_hiding = SDL_FALSE;
  1858     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1859 }
  1860 
  1861 void
  1862 SDL_RaiseWindow(SDL_Window * window)
  1863 {
  1864     CHECK_WINDOW_MAGIC(window,);
  1865 
  1866     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1867         return;
  1868     }
  1869     if (_this->RaiseWindow) {
  1870         _this->RaiseWindow(_this, window);
  1871     }
  1872 }
  1873 
  1874 void
  1875 SDL_MaximizeWindow(SDL_Window * window)
  1876 {
  1877     CHECK_WINDOW_MAGIC(window,);
  1878 
  1879     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1880         return;
  1881     }
  1882 
  1883     /* !!! FIXME: should this check if the window is resizable? */
  1884 
  1885     if (_this->MaximizeWindow) {
  1886         _this->MaximizeWindow(_this, window);
  1887     }
  1888 }
  1889 
  1890 void
  1891 SDL_MinimizeWindow(SDL_Window * window)
  1892 {
  1893     CHECK_WINDOW_MAGIC(window,);
  1894 
  1895     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1896         return;
  1897     }
  1898 
  1899     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1900 
  1901     if (_this->MinimizeWindow) {
  1902         _this->MinimizeWindow(_this, window);
  1903     }
  1904 }
  1905 
  1906 void
  1907 SDL_RestoreWindow(SDL_Window * window)
  1908 {
  1909     CHECK_WINDOW_MAGIC(window,);
  1910 
  1911     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1912         return;
  1913     }
  1914 
  1915     if (_this->RestoreWindow) {
  1916         _this->RestoreWindow(_this, window);
  1917     }
  1918 }
  1919 
  1920 int
  1921 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1922 {
  1923     CHECK_WINDOW_MAGIC(window, -1);
  1924 
  1925     flags &= FULLSCREEN_MASK;
  1926 
  1927     if (flags == (window->flags & FULLSCREEN_MASK)) {
  1928         return 0;
  1929     }
  1930 
  1931     /* clear the previous flags and OR in the new ones */
  1932     window->flags &= ~FULLSCREEN_MASK;
  1933     window->flags |= flags;
  1934 
  1935     return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1936 }
  1937 
  1938 static SDL_Surface *
  1939 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1940 {
  1941     Uint32 format;
  1942     void *pixels;
  1943     int pitch;
  1944     int bpp;
  1945     Uint32 Rmask, Gmask, Bmask, Amask;
  1946 
  1947     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1948         return NULL;
  1949     }
  1950 
  1951     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1952         return NULL;
  1953     }
  1954 
  1955     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1956         return NULL;
  1957     }
  1958 
  1959     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1960 }
  1961 
  1962 SDL_Surface *
  1963 SDL_GetWindowSurface(SDL_Window * window)
  1964 {
  1965     CHECK_WINDOW_MAGIC(window, NULL);
  1966 
  1967     if (!window->surface_valid) {
  1968         if (window->surface) {
  1969             window->surface->flags &= ~SDL_DONTFREE;
  1970             SDL_FreeSurface(window->surface);
  1971         }
  1972         window->surface = SDL_CreateWindowFramebuffer(window);
  1973         if (window->surface) {
  1974             window->surface_valid = SDL_TRUE;
  1975             window->surface->flags |= SDL_DONTFREE;
  1976         }
  1977     }
  1978     return window->surface;
  1979 }
  1980 
  1981 int
  1982 SDL_UpdateWindowSurface(SDL_Window * window)
  1983 {
  1984     SDL_Rect full_rect;
  1985 
  1986     CHECK_WINDOW_MAGIC(window, -1);
  1987 
  1988     full_rect.x = 0;
  1989     full_rect.y = 0;
  1990     full_rect.w = window->w;
  1991     full_rect.h = window->h;
  1992     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1993 }
  1994 
  1995 int
  1996 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  1997                              int numrects)
  1998 {
  1999     CHECK_WINDOW_MAGIC(window, -1);
  2000 
  2001     if (!window->surface_valid) {
  2002         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  2003     }
  2004 
  2005     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  2006 }
  2007 
  2008 int
  2009 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  2010 {
  2011     Uint16 ramp[256];
  2012     int status;
  2013 
  2014     CHECK_WINDOW_MAGIC(window, -1);
  2015 
  2016     SDL_CalculateGammaRamp(brightness, ramp);
  2017     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  2018     if (status == 0) {
  2019         window->brightness = brightness;
  2020     }
  2021     return status;
  2022 }
  2023 
  2024 float
  2025 SDL_GetWindowBrightness(SDL_Window * window)
  2026 {
  2027     CHECK_WINDOW_MAGIC(window, 1.0f);
  2028 
  2029     return window->brightness;
  2030 }
  2031 
  2032 int
  2033 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  2034                                             const Uint16 * green,
  2035                                             const Uint16 * blue)
  2036 {
  2037     CHECK_WINDOW_MAGIC(window, -1);
  2038 
  2039     if (!_this->SetWindowGammaRamp) {
  2040         return SDL_Unsupported();
  2041     }
  2042 
  2043     if (!window->gamma) {
  2044         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  2045             return -1;
  2046         }
  2047     }
  2048 
  2049     if (red) {
  2050         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  2051     }
  2052     if (green) {
  2053         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  2054     }
  2055     if (blue) {
  2056         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  2057     }
  2058     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2059         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  2060     } else {
  2061         return 0;
  2062     }
  2063 }
  2064 
  2065 int
  2066 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  2067                                             Uint16 * green,
  2068                                             Uint16 * blue)
  2069 {
  2070     CHECK_WINDOW_MAGIC(window, -1);
  2071 
  2072     if (!window->gamma) {
  2073         int i;
  2074 
  2075         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  2076         if (!window->gamma) {
  2077             return SDL_OutOfMemory();
  2078         }
  2079         window->saved_gamma = window->gamma + 3*256;
  2080 
  2081         if (_this->GetWindowGammaRamp) {
  2082             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  2083                 return -1;
  2084             }
  2085         } else {
  2086             /* Create an identity gamma ramp */
  2087             for (i = 0; i < 256; ++i) {
  2088                 Uint16 value = (Uint16)((i << 8) | i);
  2089 
  2090                 window->gamma[0*256+i] = value;
  2091                 window->gamma[1*256+i] = value;
  2092                 window->gamma[2*256+i] = value;
  2093             }
  2094         }
  2095         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  2096     }
  2097 
  2098     if (red) {
  2099         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  2100     }
  2101     if (green) {
  2102         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  2103     }
  2104     if (blue) {
  2105         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  2106     }
  2107     return 0;
  2108 }
  2109 
  2110 void
  2111 SDL_UpdateWindowGrab(SDL_Window * window)
  2112 {
  2113     if (_this->SetWindowGrab) {
  2114         SDL_bool grabbed;
  2115         if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
  2116              (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  2117             grabbed = SDL_TRUE;
  2118         } else {
  2119             grabbed = SDL_FALSE;
  2120         }
  2121         _this->SetWindowGrab(_this, window, grabbed);
  2122     }
  2123 }
  2124 
  2125 void
  2126 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  2127 {
  2128     CHECK_WINDOW_MAGIC(window,);
  2129 
  2130     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  2131         return;
  2132     }
  2133     if (grabbed) {
  2134         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  2135     } else {
  2136         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2137     }
  2138     SDL_UpdateWindowGrab(window);
  2139 }
  2140 
  2141 SDL_bool
  2142 SDL_GetWindowGrab(SDL_Window * window)
  2143 {
  2144     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2145 
  2146     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  2147 }
  2148 
  2149 void
  2150 SDL_OnWindowShown(SDL_Window * window)
  2151 {
  2152     SDL_OnWindowRestored(window);
  2153 }
  2154 
  2155 void
  2156 SDL_OnWindowHidden(SDL_Window * window)
  2157 {
  2158     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2159 }
  2160 
  2161 void
  2162 SDL_OnWindowResized(SDL_Window * window)
  2163 {
  2164     window->surface_valid = SDL_FALSE;
  2165     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2166 }
  2167 
  2168 void
  2169 SDL_OnWindowMinimized(SDL_Window * window)
  2170 {
  2171     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2172 }
  2173 
  2174 void
  2175 SDL_OnWindowRestored(SDL_Window * window)
  2176 {
  2177     /*
  2178      * FIXME: Is this fine to just remove this, or should it be preserved just
  2179      * for the fullscreen case? In principle it seems like just hiding/showing
  2180      * windows shouldn't affect the stacking order; maybe the right fix is to
  2181      * re-decouple OnWindowShown and OnWindowRestored.
  2182      */
  2183     /*SDL_RaiseWindow(window);*/
  2184 
  2185     if (FULLSCREEN_VISIBLE(window)) {
  2186         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2187     }
  2188 }
  2189 
  2190 void
  2191 SDL_OnWindowEnter(SDL_Window * window)
  2192 {
  2193     if (_this->OnWindowEnter) {
  2194         _this->OnWindowEnter(_this, window);
  2195     }
  2196 }
  2197 
  2198 void
  2199 SDL_OnWindowLeave(SDL_Window * window)
  2200 {
  2201 }
  2202 
  2203 void
  2204 SDL_OnWindowFocusGained(SDL_Window * window)
  2205 {
  2206     SDL_Mouse *mouse = SDL_GetMouse();
  2207 
  2208     if (window->gamma && _this->SetWindowGammaRamp) {
  2209         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2210     }
  2211 
  2212     if (mouse && mouse->relative_mode) {
  2213         SDL_SetMouseFocus(window);
  2214         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2215     }
  2216 
  2217     SDL_UpdateWindowGrab(window);
  2218 }
  2219 
  2220 static SDL_bool
  2221 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2222 {
  2223     const char *hint;
  2224 
  2225     if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
  2226         return SDL_FALSE;
  2227     }
  2228 
  2229 #ifdef __MACOSX__
  2230     if (Cocoa_IsWindowInFullscreenSpace(window)) {
  2231         return SDL_FALSE;
  2232     }
  2233 #endif
  2234 
  2235     hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2236     if (hint) {
  2237         if (*hint == '0') {
  2238             return SDL_FALSE;
  2239         } else {
  2240             return SDL_TRUE;
  2241         }
  2242     }
  2243 
  2244     return SDL_TRUE;
  2245 }
  2246 
  2247 void
  2248 SDL_OnWindowFocusLost(SDL_Window * window)
  2249 {
  2250     if (window->gamma && _this->SetWindowGammaRamp) {
  2251         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2252     }
  2253 
  2254     SDL_UpdateWindowGrab(window);
  2255 
  2256     if (ShouldMinimizeOnFocusLoss(window)) {
  2257         SDL_MinimizeWindow(window);
  2258     }
  2259 }
  2260 
  2261 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
  2262    !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
  2263 SDL_Window *
  2264 SDL_GetFocusWindow(void)
  2265 {
  2266     SDL_Window *window;
  2267 
  2268     if (!_this) {
  2269         return NULL;
  2270     }
  2271     for (window = _this->windows; window; window = window->next) {
  2272         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2273             return window;
  2274         }
  2275     }
  2276     return NULL;
  2277 }
  2278 
  2279 void
  2280 SDL_DestroyWindow(SDL_Window * window)
  2281 {
  2282     SDL_VideoDisplay *display;
  2283 
  2284     CHECK_WINDOW_MAGIC(window,);
  2285 
  2286     window->is_destroying = SDL_TRUE;
  2287 
  2288     /* Restore video mode, etc. */
  2289     SDL_HideWindow(window);
  2290 
  2291     /* Make sure this window no longer has focus */
  2292     if (SDL_GetKeyboardFocus() == window) {
  2293         SDL_SetKeyboardFocus(NULL);
  2294     }
  2295     if (SDL_GetMouseFocus() == window) {
  2296         SDL_SetMouseFocus(NULL);
  2297     }
  2298 
  2299     /* make no context current if this is the current context window. */
  2300     if (window->flags & SDL_WINDOW_OPENGL) {
  2301         if (_this->current_glwin == window) {
  2302             SDL_GL_MakeCurrent(window, NULL);
  2303         }
  2304     }
  2305 
  2306     if (window->surface) {
  2307         window->surface->flags &= ~SDL_DONTFREE;
  2308         SDL_FreeSurface(window->surface);
  2309     }
  2310     if (_this->DestroyWindowFramebuffer) {
  2311         _this->DestroyWindowFramebuffer(_this, window);
  2312     }
  2313     if (_this->DestroyWindow) {
  2314         _this->DestroyWindow(_this, window);
  2315     }
  2316     if (window->flags & SDL_WINDOW_OPENGL) {
  2317         SDL_GL_UnloadLibrary();
  2318     }
  2319 
  2320     display = SDL_GetDisplayForWindow(window);
  2321     if (display->fullscreen_window == window) {
  2322         display->fullscreen_window = NULL;
  2323     }
  2324 
  2325     /* Now invalidate magic */
  2326     window->magic = NULL;
  2327 
  2328     /* Free memory associated with the window */
  2329     SDL_free(window->title);
  2330     SDL_FreeSurface(window->icon);
  2331     SDL_free(window->gamma);
  2332     while (window->data) {
  2333         SDL_WindowUserData *data = window->data;
  2334 
  2335         window->data = data->next;
  2336         SDL_free(data->name);
  2337         SDL_free(data);
  2338     }
  2339 
  2340     /* Unlink the window from the list */
  2341     if (window->next) {
  2342         window->next->prev = window->prev;
  2343     }
  2344     if (window->prev) {
  2345         window->prev->next = window->next;
  2346     } else {
  2347         _this->windows = window->next;
  2348     }
  2349 
  2350     SDL_free(window);
  2351 }
  2352 
  2353 SDL_bool
  2354 SDL_IsScreenSaverEnabled()
  2355 {
  2356     if (!_this) {
  2357         return SDL_TRUE;
  2358     }
  2359     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2360 }
  2361 
  2362 void
  2363 SDL_EnableScreenSaver()
  2364 {
  2365     if (!_this) {
  2366         return;
  2367     }
  2368     if (!_this->suspend_screensaver) {
  2369         return;
  2370     }
  2371     _this->suspend_screensaver = SDL_FALSE;
  2372     if (_this->SuspendScreenSaver) {
  2373         _this->SuspendScreenSaver(_this);
  2374     }
  2375 }
  2376 
  2377 void
  2378 SDL_DisableScreenSaver()
  2379 {
  2380     if (!_this) {
  2381         return;
  2382     }
  2383     if (_this->suspend_screensaver) {
  2384         return;
  2385     }
  2386     _this->suspend_screensaver = SDL_TRUE;
  2387     if (_this->SuspendScreenSaver) {
  2388         _this->SuspendScreenSaver(_this);
  2389     }
  2390 }
  2391 
  2392 void
  2393 SDL_VideoQuit(void)
  2394 {
  2395     int i, j;
  2396 
  2397     if (!_this) {
  2398         return;
  2399     }
  2400 
  2401     /* Halt event processing before doing anything else */
  2402     SDL_TouchQuit();
  2403     SDL_MouseQuit();
  2404     SDL_KeyboardQuit();
  2405     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2406 
  2407     SDL_EnableScreenSaver();
  2408 
  2409     /* Clean up the system video */
  2410     while (_this->windows) {
  2411         SDL_DestroyWindow(_this->windows);
  2412     }
  2413     _this->VideoQuit(_this);
  2414 
  2415     for (i = 0; i < _this->num_displays; ++i) {
  2416         SDL_VideoDisplay *display = &_this->displays[i];
  2417         for (j = display->num_display_modes; j--;) {
  2418             SDL_free(display->display_modes[j].driverdata);
  2419             display->display_modes[j].driverdata = NULL;
  2420         }
  2421         SDL_free(display->display_modes);
  2422         display->display_modes = NULL;
  2423         SDL_free(display->desktop_mode.driverdata);
  2424         display->desktop_mode.driverdata = NULL;
  2425         SDL_free(display->driverdata);
  2426         display->driverdata = NULL;
  2427     }
  2428     if (_this->displays) {
  2429         for (i = 0; i < _this->num_displays; ++i) {
  2430             SDL_free(_this->displays[i].name);
  2431         }
  2432         SDL_free(_this->displays);
  2433         _this->displays = NULL;
  2434         _this->num_displays = 0;
  2435     }
  2436     SDL_free(_this->clipboard_text);
  2437     _this->clipboard_text = NULL;
  2438     _this->free(_this);
  2439     _this = NULL;
  2440 }
  2441 
  2442 int
  2443 SDL_GL_LoadLibrary(const char *path)
  2444 {
  2445     int retval;
  2446 
  2447     if (!_this) {
  2448         return SDL_UninitializedVideo();
  2449     }
  2450     if (_this->gl_config.driver_loaded) {
  2451         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2452             return SDL_SetError("OpenGL library already loaded");
  2453         }
  2454         retval = 0;
  2455     } else {
  2456         if (!_this->GL_LoadLibrary) {
  2457             return SDL_SetError("No dynamic GL support in video driver");
  2458         }
  2459         retval = _this->GL_LoadLibrary(_this, path);
  2460     }
  2461     if (retval == 0) {
  2462         ++_this->gl_config.driver_loaded;
  2463     } else {
  2464         if (_this->GL_UnloadLibrary) {
  2465             _this->GL_UnloadLibrary(_this);
  2466         }
  2467     }
  2468     return (retval);
  2469 }
  2470 
  2471 void *
  2472 SDL_GL_GetProcAddress(const char *proc)
  2473 {
  2474     void *func;
  2475 
  2476     if (!_this) {
  2477         SDL_UninitializedVideo();
  2478         return NULL;
  2479     }
  2480     func = NULL;
  2481     if (_this->GL_GetProcAddress) {
  2482         if (_this->gl_config.driver_loaded) {
  2483             func = _this->GL_GetProcAddress(_this, proc);
  2484         } else {
  2485             SDL_SetError("No GL driver has been loaded");
  2486         }
  2487     } else {
  2488         SDL_SetError("No dynamic GL support in video driver");
  2489     }
  2490     return func;
  2491 }
  2492 
  2493 void
  2494 SDL_GL_UnloadLibrary(void)
  2495 {
  2496     if (!_this) {
  2497         SDL_UninitializedVideo();
  2498         return;
  2499     }
  2500     if (_this->gl_config.driver_loaded > 0) {
  2501         if (--_this->gl_config.driver_loaded > 0) {
  2502             return;
  2503         }
  2504         if (_this->GL_UnloadLibrary) {
  2505             _this->GL_UnloadLibrary(_this);
  2506         }
  2507     }
  2508 }
  2509 
  2510 static SDL_INLINE SDL_bool
  2511 isAtLeastGL3(const char *verstr)
  2512 {
  2513     return (verstr && (SDL_atoi(verstr) >= 3));
  2514 }
  2515 
  2516 SDL_bool
  2517 SDL_GL_ExtensionSupported(const char *extension)
  2518 {
  2519 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2520     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2521     const char *extensions;
  2522     const char *start;
  2523     const char *where, *terminator;
  2524 
  2525     /* Extension names should not have spaces. */
  2526     where = SDL_strchr(extension, ' ');
  2527     if (where || *extension == '\0') {
  2528         return SDL_FALSE;
  2529     }
  2530     /* See if there's an environment variable override */
  2531     start = SDL_getenv(extension);
  2532     if (start && *start == '0') {
  2533         return SDL_FALSE;
  2534     }
  2535 
  2536     /* Lookup the available extensions */
  2537 
  2538     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2539     if (!glGetStringFunc) {
  2540         return SDL_FALSE;
  2541     }
  2542 
  2543     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2544         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2545         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2546         GLint num_exts = 0;
  2547         GLint i;
  2548 
  2549         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2550         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2551         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2552             return SDL_FALSE;
  2553         }
  2554 
  2555         #ifndef GL_NUM_EXTENSIONS
  2556         #define GL_NUM_EXTENSIONS 0x821D
  2557         #endif
  2558         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2559         for (i = 0; i < num_exts; i++) {
  2560             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2561             if (SDL_strcmp(thisext, extension) == 0) {
  2562                 return SDL_TRUE;
  2563             }
  2564         }
  2565 
  2566         return SDL_FALSE;
  2567     }
  2568 
  2569     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2570 
  2571     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2572     if (!extensions) {
  2573         return SDL_FALSE;
  2574     }
  2575     /*
  2576      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2577      * extensions string. Don't be fooled by sub-strings, etc.
  2578      */
  2579 
  2580     start = extensions;
  2581 
  2582     for (;;) {
  2583         where = SDL_strstr(start, extension);
  2584         if (!where)
  2585             break;
  2586 
  2587         terminator = where + SDL_strlen(extension);
  2588         if (where == start || *(where - 1) == ' ')
  2589             if (*terminator == ' ' || *terminator == '\0')
  2590                 return SDL_TRUE;
  2591 
  2592         start = terminator;
  2593     }
  2594     return SDL_FALSE;
  2595 #else
  2596     return SDL_FALSE;
  2597 #endif
  2598 }
  2599 
  2600 void
  2601 SDL_GL_ResetAttributes()
  2602 {
  2603     if (!_this) {
  2604         return;
  2605     }
  2606 
  2607     _this->gl_config.red_size = 3;
  2608     _this->gl_config.green_size = 3;
  2609     _this->gl_config.blue_size = 2;
  2610     _this->gl_config.alpha_size = 0;
  2611     _this->gl_config.buffer_size = 0;
  2612     _this->gl_config.depth_size = 16;
  2613     _this->gl_config.stencil_size = 0;
  2614     _this->gl_config.double_buffer = 1;
  2615     _this->gl_config.accum_red_size = 0;
  2616     _this->gl_config.accum_green_size = 0;
  2617     _this->gl_config.accum_blue_size = 0;
  2618     _this->gl_config.accum_alpha_size = 0;
  2619     _this->gl_config.stereo = 0;
  2620     _this->gl_config.multisamplebuffers = 0;
  2621     _this->gl_config.multisamplesamples = 0;
  2622     _this->gl_config.retained_backing = 1;
  2623     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
  2624     _this->gl_config.profile_mask = 0;
  2625 #if SDL_VIDEO_OPENGL
  2626     _this->gl_config.major_version = 2;
  2627     _this->gl_config.minor_version = 1;
  2628 #elif SDL_VIDEO_OPENGL_ES2
  2629     _this->gl_config.major_version = 2;
  2630     _this->gl_config.minor_version = 0;
  2631     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2632 #elif SDL_VIDEO_OPENGL_ES
  2633     _this->gl_config.major_version = 1;
  2634     _this->gl_config.minor_version = 1;
  2635     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2636 #endif
  2637     _this->gl_config.flags = 0;
  2638     _this->gl_config.framebuffer_srgb_capable = 0;
  2639 
  2640     _this->gl_config.share_with_current_context = 0;
  2641 }
  2642 
  2643 int
  2644 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2645 {
  2646 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2647     int retval;
  2648 
  2649     if (!_this) {
  2650         return SDL_UninitializedVideo();
  2651     }
  2652     retval = 0;
  2653     switch (attr) {
  2654     case SDL_GL_RED_SIZE:
  2655         _this->gl_config.red_size = value;
  2656         break;
  2657     case SDL_GL_GREEN_SIZE:
  2658         _this->gl_config.green_size = value;
  2659         break;
  2660     case SDL_GL_BLUE_SIZE:
  2661         _this->gl_config.blue_size = value;
  2662         break;
  2663     case SDL_GL_ALPHA_SIZE:
  2664         _this->gl_config.alpha_size = value;
  2665         break;
  2666     case SDL_GL_DOUBLEBUFFER:
  2667         _this->gl_config.double_buffer = value;
  2668         break;
  2669     case SDL_GL_BUFFER_SIZE:
  2670         _this->gl_config.buffer_size = value;
  2671         break;
  2672     case SDL_GL_DEPTH_SIZE:
  2673         _this->gl_config.depth_size = value;
  2674         break;
  2675     case SDL_GL_STENCIL_SIZE:
  2676         _this->gl_config.stencil_size = value;
  2677         break;
  2678     case SDL_GL_ACCUM_RED_SIZE:
  2679         _this->gl_config.accum_red_size = value;
  2680         break;
  2681     case SDL_GL_ACCUM_GREEN_SIZE:
  2682         _this->gl_config.accum_green_size = value;
  2683         break;
  2684     case SDL_GL_ACCUM_BLUE_SIZE:
  2685         _this->gl_config.accum_blue_size = value;
  2686         break;
  2687     case SDL_GL_ACCUM_ALPHA_SIZE:
  2688         _this->gl_config.accum_alpha_size = value;
  2689         break;
  2690     case SDL_GL_STEREO:
  2691         _this->gl_config.stereo = value;
  2692         break;
  2693     case SDL_GL_MULTISAMPLEBUFFERS:
  2694         _this->gl_config.multisamplebuffers = value;
  2695         break;
  2696     case SDL_GL_MULTISAMPLESAMPLES:
  2697         _this->gl_config.multisamplesamples = value;
  2698         break;
  2699     case SDL_GL_ACCELERATED_VISUAL:
  2700         _this->gl_config.accelerated = value;
  2701         break;
  2702     case SDL_GL_RETAINED_BACKING:
  2703         _this->gl_config.retained_backing = value;
  2704         break;
  2705     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2706         _this->gl_config.major_version = value;
  2707         break;
  2708     case SDL_GL_CONTEXT_MINOR_VERSION:
  2709         _this->gl_config.minor_version = value;
  2710         break;
  2711     case SDL_GL_CONTEXT_EGL:
  2712         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2713         if (value != 0) {
  2714             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  2715         } else {
  2716             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  2717         };
  2718         break;
  2719     case SDL_GL_CONTEXT_FLAGS:
  2720         if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2721                       SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2722                       SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2723                       SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
  2724             retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2725             break;
  2726         }
  2727         _this->gl_config.flags = value;
  2728         break;
  2729     case SDL_GL_CONTEXT_PROFILE_MASK:
  2730         if (value != 0 &&
  2731             value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2732             value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2733             value != SDL_GL_CONTEXT_PROFILE_ES) {
  2734             retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2735             break;
  2736         }
  2737         _this->gl_config.profile_mask = value;
  2738         break;
  2739     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2740         _this->gl_config.share_with_current_context = value;
  2741         break;
  2742     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2743         _this->gl_config.framebuffer_srgb_capable = value;
  2744         break;
  2745     default:
  2746         retval = SDL_SetError("Unknown OpenGL attribute");
  2747         break;
  2748     }
  2749     return retval;
  2750 #else
  2751     return SDL_Unsupported();
  2752 #endif /* SDL_VIDEO_OPENGL */
  2753 }
  2754 
  2755 int
  2756 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2757 {
  2758 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2759     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2760     GLenum(APIENTRY * glGetErrorFunc) (void);
  2761     GLenum attrib = 0;
  2762     GLenum error = 0;
  2763 
  2764     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2765     if (!glGetIntegervFunc) {
  2766         return -1;
  2767     }
  2768 
  2769     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2770     if (!glGetErrorFunc) {
  2771         return -1;
  2772     }
  2773 
  2774     /* Clear value in any case */
  2775     *value = 0;
  2776 
  2777     switch (attr) {
  2778     case SDL_GL_RED_SIZE:
  2779         attrib = GL_RED_BITS;
  2780         break;
  2781     case SDL_GL_BLUE_SIZE:
  2782         attrib = GL_BLUE_BITS;
  2783         break;
  2784     case SDL_GL_GREEN_SIZE:
  2785         attrib = GL_GREEN_BITS;
  2786         break;
  2787     case SDL_GL_ALPHA_SIZE:
  2788         attrib = GL_ALPHA_BITS;
  2789         break;
  2790     case SDL_GL_DOUBLEBUFFER:
  2791 #if SDL_VIDEO_OPENGL
  2792         attrib = GL_DOUBLEBUFFER;
  2793         break;
  2794 #else
  2795         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2796         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2797         /* SDL driver must set proper value after initialization              */
  2798         *value = _this->gl_config.double_buffer;
  2799         return 0;
  2800 #endif
  2801     case SDL_GL_DEPTH_SIZE:
  2802         attrib = GL_DEPTH_BITS;
  2803         break;
  2804     case SDL_GL_STENCIL_SIZE:
  2805         attrib = GL_STENCIL_BITS;
  2806         break;
  2807 #if SDL_VIDEO_OPENGL
  2808     case SDL_GL_ACCUM_RED_SIZE:
  2809         attrib = GL_ACCUM_RED_BITS;
  2810         break;
  2811     case SDL_GL_ACCUM_GREEN_SIZE:
  2812         attrib = GL_ACCUM_GREEN_BITS;
  2813         break;
  2814     case SDL_GL_ACCUM_BLUE_SIZE:
  2815         attrib = GL_ACCUM_BLUE_BITS;
  2816         break;
  2817     case SDL_GL_ACCUM_ALPHA_SIZE:
  2818         attrib = GL_ACCUM_ALPHA_BITS;
  2819         break;
  2820     case SDL_GL_STEREO:
  2821         attrib = GL_STEREO;
  2822         break;
  2823 #else
  2824     case SDL_GL_ACCUM_RED_SIZE:
  2825     case SDL_GL_ACCUM_GREEN_SIZE:
  2826     case SDL_GL_ACCUM_BLUE_SIZE:
  2827     case SDL_GL_ACCUM_ALPHA_SIZE:
  2828     case SDL_GL_STEREO:
  2829         /* none of these are supported in OpenGL ES */
  2830         *value = 0;
  2831         return 0;
  2832 #endif
  2833     case SDL_GL_MULTISAMPLEBUFFERS:
  2834 #if SDL_VIDEO_OPENGL
  2835         attrib = GL_SAMPLE_BUFFERS_ARB;
  2836 #else
  2837         attrib = GL_SAMPLE_BUFFERS;
  2838 #endif
  2839         break;
  2840     case SDL_GL_MULTISAMPLESAMPLES:
  2841 #if SDL_VIDEO_OPENGL
  2842         attrib = GL_SAMPLES_ARB;
  2843 #else
  2844         attrib = GL_SAMPLES;
  2845 #endif
  2846         break;
  2847     case SDL_GL_BUFFER_SIZE:
  2848         {
  2849             GLint bits = 0;
  2850             GLint component;
  2851 
  2852             /*
  2853              * there doesn't seem to be a single flag in OpenGL
  2854              * for this!
  2855              */
  2856             glGetIntegervFunc(GL_RED_BITS, &component);
  2857             bits += component;
  2858             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2859             bits += component;
  2860             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2861             bits += component;
  2862             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2863             bits += component;
  2864 
  2865             *value = bits;
  2866             return 0;
  2867         }
  2868     case SDL_GL_ACCELERATED_VISUAL:
  2869         {
  2870             /* FIXME: How do we get this information? */
  2871             *value = (_this->gl_config.accelerated != 0);
  2872             return 0;
  2873         }
  2874     case SDL_GL_RETAINED_BACKING:
  2875         {
  2876             *value = _this->gl_config.retained_backing;
  2877             return 0;
  2878         }
  2879     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2880         {
  2881             *value = _this->gl_config.major_version;
  2882             return 0;
  2883         }
  2884     case SDL_GL_CONTEXT_MINOR_VERSION:
  2885         {
  2886             *value = _this->gl_config.minor_version;
  2887             return 0;
  2888         }
  2889     case SDL_GL_CONTEXT_EGL:
  2890         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2891         {
  2892             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  2893                 *value = 1;
  2894             }
  2895             else {
  2896                 *value = 0;
  2897             }
  2898             return 0;
  2899         }
  2900     case SDL_GL_CONTEXT_FLAGS:
  2901         {
  2902             *value = _this->gl_config.flags;
  2903             return 0;
  2904         }
  2905     case SDL_GL_CONTEXT_PROFILE_MASK:
  2906         {
  2907             *value = _this->gl_config.profile_mask;
  2908             return 0;
  2909         }
  2910     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2911         {
  2912             *value = _this->gl_config.share_with_current_context;
  2913             return 0;
  2914         }
  2915     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2916         {
  2917             *value = _this->gl_config.framebuffer_srgb_capable;
  2918             return 0;
  2919         }
  2920     default:
  2921         return SDL_SetError("Unknown OpenGL attribute");
  2922     }
  2923 
  2924     glGetIntegervFunc(attrib, (GLint *) value);
  2925     error = glGetErrorFunc();
  2926     if (error != GL_NO_ERROR) {
  2927         if (error == GL_INVALID_ENUM) {
  2928             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2929         } else if (error == GL_INVALID_VALUE) {
  2930             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2931         }
  2932         return SDL_SetError("OpenGL error: %08X", error);
  2933     }
  2934     return 0;
  2935 #else
  2936     return SDL_Unsupported();
  2937 #endif /* SDL_VIDEO_OPENGL */
  2938 }
  2939 
  2940 SDL_GLContext
  2941 SDL_GL_CreateContext(SDL_Window * window)
  2942 {
  2943     SDL_GLContext ctx = NULL;
  2944     CHECK_WINDOW_MAGIC(window, NULL);
  2945 
  2946     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2947         SDL_SetError("The specified window isn't an OpenGL window");
  2948         return NULL;
  2949     }
  2950 
  2951     ctx = _this->GL_CreateContext(_this, window);
  2952 
  2953     /* Creating a context is assumed to make it current in the SDL driver. */
  2954     if (ctx) {
  2955         _this->current_glwin = window;
  2956         _this->current_glctx = ctx;
  2957         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2958         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2959     }
  2960     return ctx;
  2961 }
  2962 
  2963 int
  2964 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2965 {
  2966     int retval;
  2967 
  2968     if (window == SDL_GL_GetCurrentWindow() &&
  2969         ctx == SDL_GL_GetCurrentContext()) {
  2970         /* We're already current. */
  2971         return 0;
  2972     }
  2973 
  2974     if (!ctx) {
  2975         window = NULL;
  2976     } else {
  2977         CHECK_WINDOW_MAGIC(window, -1);
  2978 
  2979         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2980             return SDL_SetError("The specified window isn't an OpenGL window");
  2981         }
  2982     }
  2983 
  2984     retval = _this->GL_MakeCurrent(_this, window, ctx);
  2985     if (retval == 0) {
  2986         _this->current_glwin = window;
  2987         _this->current_glctx = ctx;
  2988         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2989         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2990     }
  2991     return retval;
  2992 }
  2993 
  2994 SDL_Window *
  2995 SDL_GL_GetCurrentWindow(void)
  2996 {
  2997     if (!_this) {
  2998         SDL_UninitializedVideo();
  2999         return NULL;
  3000     }
  3001     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  3002 }
  3003 
  3004 SDL_GLContext
  3005 SDL_GL_GetCurrentContext(void)
  3006 {
  3007     if (!_this) {
  3008         SDL_UninitializedVideo();
  3009         return NULL;
  3010     }
  3011     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  3012 }
  3013 
  3014 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  3015 {
  3016     CHECK_WINDOW_MAGIC(window,);
  3017 
  3018     if (_this->GL_GetDrawableSize) {
  3019         _this->GL_GetDrawableSize(_this, window, w, h);
  3020     } else {
  3021         SDL_GetWindowSize(window, w, h);
  3022     }
  3023 }
  3024 
  3025 int
  3026 SDL_GL_SetSwapInterval(int interval)
  3027 {
  3028     if (!_this) {
  3029         return SDL_UninitializedVideo();
  3030     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3031         return SDL_SetError("No OpenGL context has been made current");
  3032     } else if (_this->GL_SetSwapInterval) {
  3033         return _this->GL_SetSwapInterval(_this, interval);
  3034     } else {
  3035         return SDL_SetError("Setting the swap interval is not supported");
  3036     }
  3037 }
  3038 
  3039 int
  3040 SDL_GL_GetSwapInterval(void)
  3041 {
  3042     if (!_this) {
  3043         return 0;
  3044     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3045         return 0;
  3046     } else if (_this->GL_GetSwapInterval) {
  3047         return _this->GL_GetSwapInterval(_this);
  3048     } else {
  3049         return 0;
  3050     }
  3051 }
  3052 
  3053 void
  3054 SDL_GL_SwapWindow(SDL_Window * window)
  3055 {
  3056     CHECK_WINDOW_MAGIC(window,);
  3057 
  3058     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3059         SDL_SetError("The specified window isn't an OpenGL window");
  3060         return;
  3061     }
  3062 
  3063     if (SDL_GL_GetCurrentWindow() != window) {
  3064         SDL_SetError("The specified window has not been made current");
  3065         return;
  3066     }
  3067 
  3068     _this->GL_SwapWindow(_this, window);
  3069 }
  3070 
  3071 void
  3072 SDL_GL_DeleteContext(SDL_GLContext context)
  3073 {
  3074     if (!_this || !context) {
  3075         return;
  3076     }
  3077 
  3078     if (SDL_GL_GetCurrentContext() == context) {
  3079         SDL_GL_MakeCurrent(NULL, NULL);
  3080     }
  3081 
  3082     _this->GL_DeleteContext(_this, context);
  3083 }
  3084 
  3085 #if 0                           /* FIXME */
  3086 /*
  3087  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  3088  * & 2 for alpha channel.
  3089  */
  3090 static void
  3091 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  3092 {
  3093     int x, y;
  3094     Uint32 colorkey;
  3095 #define SET_MASKBIT(icon, x, y, mask) \
  3096     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  3097 
  3098     colorkey = icon->format->colorkey;
  3099     switch (icon->format->BytesPerPixel) {
  3100     case 1:
  3101         {
  3102             Uint8 *pixels;
  3103             for (y = 0; y < icon->h; ++y) {
  3104                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  3105                 for (x = 0; x < icon->w; ++x) {
  3106                     if (*pixels++ == colorkey) {
  3107                         SET_MASKBIT(icon, x, y, mask);
  3108                     }
  3109                 }
  3110             }
  3111         }
  3112         break;
  3113 
  3114     case 2:
  3115         {
  3116             Uint16 *pixels;
  3117             for (y = 0; y < icon->h; ++y) {
  3118                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3119                 for (x = 0; x < icon->w; ++x) {
  3120                     if ((flags & 1) && *pixels == colorkey) {
  3121                         SET_MASKBIT(icon, x, y, mask);
  3122                     } else if ((flags & 2)
  3123                                && (*pixels & icon->format->Amask) == 0) {
  3124                         SET_MASKBIT(icon, x, y, mask);
  3125                     }
  3126                     pixels++;
  3127                 }
  3128             }
  3129         }
  3130         break;
  3131 
  3132     case 4:
  3133         {
  3134             Uint32 *pixels;
  3135             for (y = 0; y < icon->h; ++y) {
  3136                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3137                 for (x = 0; x < icon->w; ++x) {
  3138                     if ((flags & 1) && *pixels == colorkey) {
  3139                         SET_MASKBIT(icon, x, y, mask);
  3140                     } else if ((flags & 2)
  3141                                && (*pixels & icon->format->Amask) == 0) {
  3142                         SET_MASKBIT(icon, x, y, mask);
  3143                     }
  3144                     pixels++;
  3145                 }
  3146             }
  3147         }
  3148         break;
  3149     }
  3150 }
  3151 
  3152 /*
  3153  * Sets the window manager icon for the display window.
  3154  */
  3155 void
  3156 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3157 {
  3158     if (icon && _this->SetIcon) {
  3159         /* Generate a mask if necessary, and create the icon! */
  3160         if (mask == NULL) {
  3161             int mask_len = icon->h * (icon->w + 7) / 8;
  3162             int flags = 0;
  3163             mask = (Uint8 *) SDL_malloc(mask_len);
  3164             if (mask == NULL) {
  3165                 return;
  3166             }
  3167             SDL_memset(mask, ~0, mask_len);
  3168             if (icon->flags & SDL_SRCCOLORKEY)
  3169                 flags |= 1;
  3170             if (icon->flags & SDL_SRCALPHA)
  3171                 flags |= 2;
  3172             if (flags) {
  3173                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3174             }
  3175             _this->SetIcon(_this, icon, mask);
  3176             SDL_free(mask);
  3177         } else {
  3178             _this->SetIcon(_this, icon, mask);
  3179         }
  3180     }
  3181 }
  3182 #endif
  3183 
  3184 SDL_bool
  3185 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3186 {
  3187     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3188 
  3189     if (!info) {
  3190         SDL_InvalidParamError("info");
  3191         return SDL_FALSE;
  3192     }
  3193     info->subsystem = SDL_SYSWM_UNKNOWN;
  3194 
  3195     if (!_this->GetWindowWMInfo) {
  3196         SDL_Unsupported();
  3197         return SDL_FALSE;
  3198     }
  3199     return (_this->GetWindowWMInfo(_this, window, info));
  3200 }
  3201 
  3202 void
  3203 SDL_StartTextInput(void)
  3204 {
  3205     SDL_Window *window;
  3206 
  3207     /* First, enable text events */
  3208     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3209     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3210 
  3211     /* Then show the on-screen keyboard, if any */
  3212     window = SDL_GetFocusWindow();
  3213     if (window && _this && _this->ShowScreenKeyboard) {
  3214         _this->ShowScreenKeyboard(_this, window);
  3215     }
  3216 
  3217     /* Finally start the text input system */
  3218     if (_this && _this->StartTextInput) {
  3219         _this->StartTextInput(_this);
  3220     }
  3221 }
  3222 
  3223 SDL_bool
  3224 SDL_IsTextInputActive(void)
  3225 {
  3226     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3227 }
  3228 
  3229 void
  3230 SDL_StopTextInput(void)
  3231 {
  3232     SDL_Window *window;
  3233 
  3234     /* Stop the text input system */
  3235     if (_this && _this->StopTextInput) {
  3236         _this->StopTextInput(_this);
  3237     }
  3238 
  3239     /* Hide the on-screen keyboard, if any */
  3240     window = SDL_GetFocusWindow();
  3241     if (window && _this && _this->HideScreenKeyboard) {
  3242         _this->HideScreenKeyboard(_this, window);
  3243     }
  3244 
  3245     /* Finally disable text events */
  3246     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3247     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3248 }
  3249 
  3250 void
  3251 SDL_SetTextInputRect(SDL_Rect *rect)
  3252 {
  3253     if (_this && _this->SetTextInputRect) {
  3254         _this->SetTextInputRect(_this, rect);
  3255     }
  3256 }
  3257 
  3258 SDL_bool
  3259 SDL_HasScreenKeyboardSupport(void)
  3260 {
  3261     if (_this && _this->HasScreenKeyboardSupport) {
  3262         return _this->HasScreenKeyboardSupport(_this);
  3263     }
  3264     return SDL_FALSE;
  3265 }
  3266 
  3267 SDL_bool
  3268 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3269 {
  3270     if (window && _this && _this->IsScreenKeyboardShown) {
  3271         return _this->IsScreenKeyboardShown(_this, window);
  3272     }
  3273     return SDL_FALSE;
  3274 }
  3275 
  3276 #if SDL_VIDEO_DRIVER_ANDROID
  3277 #include "android/SDL_androidmessagebox.h"
  3278 #endif
  3279 #if SDL_VIDEO_DRIVER_WINDOWS
  3280 #include "windows/SDL_windowsmessagebox.h"
  3281 #endif
  3282 #if SDL_VIDEO_DRIVER_WINRT
  3283 #include "winrt/SDL_winrtmessagebox.h"
  3284 #endif
  3285 #if SDL_VIDEO_DRIVER_COCOA
  3286 #include "cocoa/SDL_cocoamessagebox.h"
  3287 #endif
  3288 #if SDL_VIDEO_DRIVER_UIKIT
  3289 #include "uikit/SDL_uikitmessagebox.h"
  3290 #endif
  3291 #if SDL_VIDEO_DRIVER_X11
  3292 #include "x11/SDL_x11messagebox.h"
  3293 #endif
  3294 
  3295 // This function will be unused if none of the above video drivers are present.
  3296 SDL_UNUSED static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3297 {
  3298     SDL_SysWMinfo info;
  3299     SDL_Window *window = messageboxdata->window;
  3300 
  3301     if (!window) {
  3302         return SDL_TRUE;
  3303     }
  3304 
  3305     SDL_VERSION(&info.version);
  3306     if (!SDL_GetWindowWMInfo(window, &info)) {
  3307         return SDL_TRUE;
  3308     } else {
  3309         return (info.subsystem == drivertype);
  3310     }
  3311 }
  3312 
  3313 int
  3314 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3315 {
  3316     int dummybutton;
  3317     int retval = -1;
  3318     SDL_bool relative_mode;
  3319     int show_cursor_prev;
  3320     SDL_bool mouse_captured;
  3321     SDL_Window *current_window;
  3322 
  3323     if (!messageboxdata) {
  3324         return SDL_InvalidParamError("messageboxdata");
  3325     }
  3326 
  3327     current_window = SDL_GetKeyboardFocus();
  3328     mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
  3329     relative_mode = SDL_GetRelativeMouseMode();
  3330     SDL_CaptureMouse(SDL_FALSE);
  3331     SDL_SetRelativeMouseMode(SDL_FALSE);
  3332     show_cursor_prev = SDL_ShowCursor(1);
  3333 
  3334     if (!buttonid) {
  3335         buttonid = &dummybutton;
  3336     }
  3337 
  3338     if (_this && _this->ShowMessageBox) {
  3339         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3340     }
  3341 
  3342     /* It's completely fine to call this function before video is initialized */
  3343 #if SDL_VIDEO_DRIVER_ANDROID
  3344     if (retval == -1 &&
  3345         Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3346         retval = 0;
  3347     }
  3348 #endif
  3349 #if SDL_VIDEO_DRIVER_WINDOWS
  3350     if (retval == -1 &&
  3351         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3352         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3353         retval = 0;
  3354     }
  3355 #endif
  3356 #if SDL_VIDEO_DRIVER_WINRT
  3357     if (retval == -1 &&
  3358         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
  3359         WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3360         retval = 0;
  3361     }
  3362 #endif
  3363 #if SDL_VIDEO_DRIVER_COCOA
  3364     if (retval == -1 &&
  3365         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3366         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3367         retval = 0;
  3368     }
  3369 #endif
  3370 #if SDL_VIDEO_DRIVER_UIKIT
  3371     if (retval == -1 &&
  3372         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3373         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3374         retval = 0;
  3375     }
  3376 #endif
  3377 #if SDL_VIDEO_DRIVER_X11
  3378     if (retval == -1 &&
  3379         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3380         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3381         retval = 0;
  3382     }
  3383 #endif
  3384     if (retval == -1) {
  3385         SDL_SetError("No message system available");
  3386     }
  3387 
  3388     if (current_window) {
  3389         SDL_RaiseWindow(current_window);
  3390         if (mouse_captured) {
  3391             SDL_CaptureMouse(SDL_TRUE);
  3392         }
  3393     }
  3394 
  3395     SDL_ShowCursor(show_cursor_prev);
  3396     SDL_SetRelativeMouseMode(relative_mode);
  3397 
  3398     return retval;
  3399 }
  3400 
  3401 int
  3402 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3403 {
  3404     SDL_MessageBoxData data;
  3405     SDL_MessageBoxButtonData button;
  3406 
  3407     SDL_zero(data);
  3408     data.flags = flags;
  3409     data.title = title;
  3410     data.message = message;
  3411     data.numbuttons = 1;
  3412     data.buttons = &button;
  3413     data.window = window;
  3414 
  3415     SDL_zero(button);
  3416     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3417     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3418     button.text = "OK";
  3419 
  3420     return SDL_ShowMessageBox(&data, NULL);
  3421 }
  3422 
  3423 SDL_bool
  3424 SDL_ShouldAllowTopmost(void)
  3425 {
  3426     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3427     if (hint) {
  3428         if (*hint == '0') {
  3429             return SDL_FALSE;
  3430         } else {
  3431             return SDL_TRUE;
  3432         }
  3433     }
  3434     return SDL_TRUE;
  3435 }
  3436 
  3437 int
  3438 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
  3439 {
  3440     CHECK_WINDOW_MAGIC(window, -1);
  3441 
  3442     if (!_this->SetWindowHitTest) {
  3443         return SDL_Unsupported();
  3444     } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
  3445         return -1;
  3446     }
  3447 
  3448     window->hit_test = callback;
  3449     window->hit_test_data = userdata;
  3450 
  3451     return 0;
  3452 }
  3453 
  3454 /* vi: set ts=4 sw=4 expandtab: */