src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 18 Dec 2014 00:19:52 -0500
changeset 9278 8900afb78a19
parent 9164 494876610c49
child 9363 c9a4d606f6db
child 9533 e5693e855338
permissions -rw-r--r--
Initial merge of Emscripten port!

With this commit, you can compile SDL2 with Emscripten
( http://emscripten.org/ ), and make your SDL-based C/C++ program
into a web app.

This port was due to the efforts of several people, including: Charlie Birks,
Sathyanarayanan Gunasekaran, Jukka Jylänki, Alon Zakai, Edward Rudd,
Bruce Mitchener, and Martin Gerhardy. (Thanks, everyone!)
     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_EMSCRIPTEN
   102     &Emscripten_bootstrap,
   103 #endif
   104 #if SDL_VIDEO_DRIVER_DUMMY
   105     &DUMMY_bootstrap,
   106 #endif
   107     NULL
   108 };
   109 
   110 static SDL_VideoDevice *_this = NULL;
   111 
   112 #define CHECK_WINDOW_MAGIC(window, retval) \
   113     if (!_this) { \
   114         SDL_UninitializedVideo(); \
   115         return retval; \
   116     } \
   117     if (!window || window->magic != &_this->window_magic) { \
   118         SDL_SetError("Invalid window"); \
   119         return retval; \
   120     }
   121 
   122 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
   123     if (!_this) { \
   124         SDL_UninitializedVideo(); \
   125         return retval; \
   126     } \
   127     SDL_assert(_this->displays != NULL); \
   128     if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
   129         SDL_SetError("displayIndex must be in the range 0 - %d", \
   130                      _this->num_displays - 1); \
   131         return retval; \
   132     }
   133 
   134 #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
   135 
   136 #ifdef __MACOSX__
   137 /* Support for Mac OS X fullscreen spaces */
   138 extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window);
   139 extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state);
   140 #endif
   141 
   142 
   143 /* Support for framebuffer emulation using an accelerated renderer */
   144 
   145 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
   146 
   147 typedef struct {
   148     SDL_Renderer *renderer;
   149     SDL_Texture *texture;
   150     void *pixels;
   151     int pitch;
   152     int bytes_per_pixel;
   153 } SDL_WindowTextureData;
   154 
   155 static SDL_bool
   156 ShouldUseTextureFramebuffer()
   157 {
   158     const char *hint;
   159 
   160     /* If there's no native framebuffer support then there's no option */
   161     if (!_this->CreateWindowFramebuffer) {
   162         return SDL_TRUE;
   163     }
   164 
   165     /* If the user has specified a software renderer we can't use a
   166        texture framebuffer, or renderer creation will go recursive.
   167      */
   168     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   169     if (hint && SDL_strcasecmp(hint, "software") == 0) {
   170         return SDL_FALSE;
   171     }
   172 
   173     /* See if the user or application wants a specific behavior */
   174     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   175     if (hint) {
   176         if (*hint == '0') {
   177             return SDL_FALSE;
   178         } else {
   179             return SDL_TRUE;
   180         }
   181     }
   182 
   183     /* Each platform has different performance characteristics */
   184 #if defined(__WIN32__)
   185     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
   186      */
   187     return SDL_FALSE;
   188 
   189 #elif defined(__MACOSX__)
   190     /* Mac OS X uses OpenGL as the native fast path */
   191     return SDL_TRUE;
   192 
   193 #elif defined(__LINUX__)
   194     /* Properly configured OpenGL drivers are faster than MIT-SHM */
   195 #if SDL_VIDEO_OPENGL
   196     /* Ugh, find a way to cache this value! */
   197     {
   198         SDL_Window *window;
   199         SDL_GLContext context;
   200         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
   201 
   202         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
   203         if (window) {
   204             context = SDL_GL_CreateContext(window);
   205             if (context) {
   206                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
   207                 const char *vendor = NULL;
   208 
   209                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
   210                 if (glGetStringFunc) {
   211                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
   212                 }
   213                 /* Add more vendors here at will... */
   214                 if (vendor &&
   215                     (SDL_strstr(vendor, "ATI Technologies") ||
   216                      SDL_strstr(vendor, "NVIDIA"))) {
   217                     hasAcceleratedOpenGL = SDL_TRUE;
   218                 }
   219                 SDL_GL_DeleteContext(context);
   220             }
   221             SDL_DestroyWindow(window);
   222         }
   223         return hasAcceleratedOpenGL;
   224     }
   225 #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
   226     /* Let's be optimistic about this! */
   227     return SDL_TRUE;
   228 #else
   229     return SDL_FALSE;
   230 #endif
   231 
   232 #else
   233     /* Play it safe, assume that if there is a framebuffer driver that it's
   234        optimized for the current platform.
   235     */
   236     return SDL_FALSE;
   237 #endif
   238 }
   239 
   240 static int
   241 SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
   242 {
   243     SDL_WindowTextureData *data;
   244 
   245     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   246     if (!data) {
   247         SDL_Renderer *renderer = NULL;
   248         int i;
   249         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   250 
   251         /* Check to see if there's a specific driver requested */
   252         if (hint && *hint != '0' && *hint != '1' &&
   253             SDL_strcasecmp(hint, "software") != 0) {
   254             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   255                 SDL_RendererInfo info;
   256                 SDL_GetRenderDriverInfo(i, &info);
   257                 if (SDL_strcasecmp(info.name, hint) == 0) {
   258                     renderer = SDL_CreateRenderer(window, i, 0);
   259                     break;
   260                 }
   261             }
   262         }
   263         
   264         if (!renderer) {
   265             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   266                 SDL_RendererInfo info;
   267                 SDL_GetRenderDriverInfo(i, &info);
   268                 if (SDL_strcmp(info.name, "software") != 0) {
   269                     renderer = SDL_CreateRenderer(window, i, 0);
   270                     if (renderer) {
   271                         break;
   272                     }
   273                 }
   274             }
   275         }
   276         if (!renderer) {
   277             return SDL_SetError("No hardware accelerated renderers available");
   278         }
   279 
   280         /* Create the data after we successfully create the renderer (bug #1116) */
   281         data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
   282         if (!data) {
   283             SDL_DestroyRenderer(renderer);
   284             return SDL_OutOfMemory();
   285         }
   286         SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
   287 
   288         data->renderer = renderer;
   289     }
   290 
   291     /* Free any old texture and pixel data */
   292     if (data->texture) {
   293         SDL_DestroyTexture(data->texture);
   294         data->texture = NULL;
   295     }
   296     SDL_free(data->pixels);
   297     data->pixels = NULL;
   298 
   299     {
   300         SDL_RendererInfo info;
   301         Uint32 i;
   302 
   303         if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
   304             return -1;
   305         }
   306 
   307         /* Find the first format without an alpha channel */
   308         *format = info.texture_formats[0];
   309 
   310         for (i = 0; i < info.num_texture_formats; ++i) {
   311             if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
   312                     !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
   313                 *format = info.texture_formats[i];
   314                 break;
   315             }
   316         }
   317     }
   318 
   319     data->texture = SDL_CreateTexture(data->renderer, *format,
   320                                       SDL_TEXTUREACCESS_STREAMING,
   321                                       window->w, window->h);
   322     if (!data->texture) {
   323         return -1;
   324     }
   325 
   326     /* Create framebuffer data */
   327     data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
   328     data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
   329     data->pixels = SDL_malloc(window->h * data->pitch);
   330     if (!data->pixels) {
   331         return SDL_OutOfMemory();
   332     }
   333 
   334     *pixels = data->pixels;
   335     *pitch = data->pitch;
   336 
   337     /* Make sure we're not double-scaling the viewport */
   338     SDL_RenderSetViewport(data->renderer, NULL);
   339 
   340     return 0;
   341 }
   342 
   343 static int
   344 SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects)
   345 {
   346     SDL_WindowTextureData *data;
   347     SDL_Rect rect;
   348     void *src;
   349 
   350     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   351     if (!data || !data->texture) {
   352         return SDL_SetError("No window texture data");
   353     }
   354 
   355     /* Update a single rect that contains subrects for best DMA performance */
   356     if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
   357         src = (void *)((Uint8 *)data->pixels +
   358                         rect.y * data->pitch +
   359                         rect.x * data->bytes_per_pixel);
   360         if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
   361             return -1;
   362         }
   363 
   364         if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
   365             return -1;
   366         }
   367 
   368         SDL_RenderPresent(data->renderer);
   369     }
   370     return 0;
   371 }
   372 
   373 static void
   374 SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window)
   375 {
   376     SDL_WindowTextureData *data;
   377 
   378     data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
   379     if (!data) {
   380         return;
   381     }
   382     if (data->texture) {
   383         SDL_DestroyTexture(data->texture);
   384     }
   385     if (data->renderer) {
   386         SDL_DestroyRenderer(data->renderer);
   387     }
   388     SDL_free(data->pixels);
   389     SDL_free(data);
   390 }
   391 
   392 
   393 static int
   394 cmpmodes(const void *A, const void *B)
   395 {
   396     const SDL_DisplayMode *a = (const SDL_DisplayMode *) A;
   397     const SDL_DisplayMode *b = (const SDL_DisplayMode *) B;
   398     if (a == b) {
   399         return 0;
   400     } else if (a->w != b->w) {
   401         return b->w - a->w;
   402     } else if (a->h != b->h) {
   403         return b->h - a->h;
   404     } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) {
   405         return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format);
   406     } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) {
   407         return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format);
   408     } else if (a->refresh_rate != b->refresh_rate) {
   409         return b->refresh_rate - a->refresh_rate;
   410     }
   411     return 0;
   412 }
   413 
   414 static int
   415 SDL_UninitializedVideo()
   416 {
   417     return SDL_SetError("Video subsystem has not been initialized");
   418 }
   419 
   420 int
   421 SDL_GetNumVideoDrivers(void)
   422 {
   423     return SDL_arraysize(bootstrap) - 1;
   424 }
   425 
   426 const char *
   427 SDL_GetVideoDriver(int index)
   428 {
   429     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   430         return bootstrap[index]->name;
   431     }
   432     return NULL;
   433 }
   434 
   435 /*
   436  * Initialize the video and event subsystems -- determine native pixel format
   437  */
   438 int
   439 SDL_VideoInit(const char *driver_name)
   440 {
   441     SDL_VideoDevice *video;
   442     const char *hint;
   443     int index;
   444     int i;
   445     SDL_bool allow_screensaver;
   446 
   447     /* Check to make sure we don't overwrite '_this' */
   448     if (_this != NULL) {
   449         SDL_VideoQuit();
   450     }
   451 
   452 #if !SDL_TIMERS_DISABLED
   453     SDL_TicksInit();
   454 #endif
   455 
   456     /* Start the event loop */
   457     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||
   458         SDL_KeyboardInit() < 0 ||
   459         SDL_MouseInit() < 0 ||
   460         SDL_TouchInit() < 0) {
   461         return -1;
   462     }
   463 
   464     /* Select the proper video driver */
   465     index = 0;
   466     video = NULL;
   467     if (driver_name == NULL) {
   468         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   469     }
   470     if (driver_name != NULL) {
   471         for (i = 0; bootstrap[i]; ++i) {
   472             if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {
   473                 if (bootstrap[i]->available()) {
   474                     video = bootstrap[i]->create(index);
   475                     break;
   476                 }
   477             }
   478         }
   479     } else {
   480         for (i = 0; bootstrap[i]; ++i) {
   481             if (bootstrap[i]->available()) {
   482                 video = bootstrap[i]->create(index);
   483                 if (video != NULL) {
   484                     break;
   485                 }
   486             }
   487         }
   488     }
   489     if (video == NULL) {
   490         if (driver_name) {
   491             return SDL_SetError("%s not available", driver_name);
   492         }
   493         return SDL_SetError("No available video device");
   494     }
   495     _this = video;
   496     _this->name = bootstrap[i]->name;
   497     _this->next_object_id = 1;
   498 
   499 
   500     /* Set some very sane GL defaults */
   501     _this->gl_config.driver_loaded = 0;
   502     _this->gl_config.dll_handle = NULL;
   503     SDL_GL_ResetAttributes();
   504 
   505     _this->current_glwin_tls = SDL_TLSCreate();
   506     _this->current_glctx_tls = SDL_TLSCreate();
   507 
   508     /* Initialize the video subsystem */
   509     if (_this->VideoInit(_this) < 0) {
   510         SDL_VideoQuit();
   511         return -1;
   512     }
   513 
   514     /* Make sure some displays were added */
   515     if (_this->num_displays == 0) {
   516         SDL_VideoQuit();
   517         return SDL_SetError("The video driver did not add any displays");
   518     }
   519 
   520     /* Add the renderer framebuffer emulation if desired */
   521     if (ShouldUseTextureFramebuffer()) {
   522         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
   523         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
   524         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
   525     }
   526 
   527     /* Disable the screen saver by default. This is a change from <= 2.0.1,
   528        but most things using SDL are games or media players; you wouldn't
   529        want a screensaver to trigger if you're playing exclusively with a
   530        joystick, or passively watching a movie. Things that use SDL but
   531        function more like a normal desktop app should explicitly reenable the
   532        screensaver. */
   533     hint = SDL_GetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER);
   534     if (hint) {
   535         allow_screensaver = SDL_atoi(hint) ? SDL_TRUE : SDL_FALSE;
   536     } else {
   537         allow_screensaver = SDL_FALSE;
   538     }
   539     if (!allow_screensaver) {
   540         SDL_DisableScreenSaver();
   541     }
   542 
   543     /* If we don't use a screen keyboard, turn on text input by default,
   544        otherwise programs that expect to get text events without enabling
   545        UNICODE input won't get any events.
   546 
   547        Actually, come to think of it, you needed to call SDL_EnableUNICODE(1)
   548        in SDL 1.2 before you got text input events.  Hmm...
   549      */
   550     if (!SDL_HasScreenKeyboardSupport()) {
   551         SDL_StartTextInput();
   552     }
   553 
   554     /* We're ready to go! */
   555     return 0;
   556 }
   557 
   558 const char *
   559 SDL_GetCurrentVideoDriver()
   560 {
   561     if (!_this) {
   562         SDL_UninitializedVideo();
   563         return NULL;
   564     }
   565     return _this->name;
   566 }
   567 
   568 SDL_VideoDevice *
   569 SDL_GetVideoDevice(void)
   570 {
   571     return _this;
   572 }
   573 
   574 int
   575 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   576 {
   577     SDL_VideoDisplay display;
   578 
   579     SDL_zero(display);
   580     if (desktop_mode) {
   581         display.desktop_mode = *desktop_mode;
   582     }
   583     display.current_mode = display.desktop_mode;
   584 
   585     return SDL_AddVideoDisplay(&display);
   586 }
   587 
   588 int
   589 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   590 {
   591     SDL_VideoDisplay *displays;
   592     int index = -1;
   593 
   594     displays =
   595         SDL_realloc(_this->displays,
   596                     (_this->num_displays + 1) * sizeof(*displays));
   597     if (displays) {
   598         index = _this->num_displays++;
   599         displays[index] = *display;
   600         displays[index].device = _this;
   601         _this->displays = displays;
   602 
   603         if (display->name) {
   604             displays[index].name = SDL_strdup(display->name);
   605         } else {
   606             char name[32];
   607 
   608             SDL_itoa(index, name, 10);
   609             displays[index].name = SDL_strdup(name);
   610         }
   611     } else {
   612         SDL_OutOfMemory();
   613     }
   614     return index;
   615 }
   616 
   617 int
   618 SDL_GetNumVideoDisplays(void)
   619 {
   620     if (!_this) {
   621         SDL_UninitializedVideo();
   622         return 0;
   623     }
   624     return _this->num_displays;
   625 }
   626 
   627 static int
   628 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   629 {
   630     int displayIndex;
   631 
   632     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   633         if (display == &_this->displays[displayIndex]) {
   634             return displayIndex;
   635         }
   636     }
   637 
   638     /* Couldn't find the display, just use index 0 */
   639     return 0;
   640 }
   641 
   642 void *
   643 SDL_GetDisplayDriverData(int displayIndex)
   644 {
   645     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   646 
   647     return _this->displays[displayIndex].driverdata;
   648 }
   649 
   650 const char *
   651 SDL_GetDisplayName(int displayIndex)
   652 {
   653     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   654 
   655     return _this->displays[displayIndex].name;
   656 }
   657 
   658 int
   659 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   660 {
   661     CHECK_DISPLAY_INDEX(displayIndex, -1);
   662 
   663     if (rect) {
   664         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   665 
   666         if (_this->GetDisplayBounds) {
   667             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   668                 return 0;
   669             }
   670         }
   671 
   672         /* Assume that the displays are left to right */
   673         if (displayIndex == 0) {
   674             rect->x = 0;
   675             rect->y = 0;
   676         } else {
   677             SDL_GetDisplayBounds(displayIndex-1, rect);
   678             rect->x += rect->w;
   679         }
   680         rect->w = display->current_mode.w;
   681         rect->h = display->current_mode.h;
   682     }
   683     return 0;
   684 }
   685 
   686 SDL_bool
   687 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   688 {
   689     SDL_DisplayMode *modes;
   690     int i, nmodes;
   691 
   692     /* Make sure we don't already have the mode in the list */
   693     modes = display->display_modes;
   694     nmodes = display->num_display_modes;
   695     for (i = 0; i < nmodes; ++i) {
   696         if (cmpmodes(mode, &modes[i]) == 0) {
   697             return SDL_FALSE;
   698         }
   699     }
   700 
   701     /* Go ahead and add the new mode */
   702     if (nmodes == display->max_display_modes) {
   703         modes =
   704             SDL_realloc(modes,
   705                         (display->max_display_modes + 32) * sizeof(*modes));
   706         if (!modes) {
   707             return SDL_FALSE;
   708         }
   709         display->display_modes = modes;
   710         display->max_display_modes += 32;
   711     }
   712     modes[nmodes] = *mode;
   713     display->num_display_modes++;
   714 
   715     /* Re-sort video modes */
   716     SDL_qsort(display->display_modes, display->num_display_modes,
   717               sizeof(SDL_DisplayMode), cmpmodes);
   718 
   719     return SDL_TRUE;
   720 }
   721 
   722 static int
   723 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   724 {
   725     if (!display->num_display_modes && _this->GetDisplayModes) {
   726         _this->GetDisplayModes(_this, display);
   727         SDL_qsort(display->display_modes, display->num_display_modes,
   728                   sizeof(SDL_DisplayMode), cmpmodes);
   729     }
   730     return display->num_display_modes;
   731 }
   732 
   733 int
   734 SDL_GetNumDisplayModes(int displayIndex)
   735 {
   736     CHECK_DISPLAY_INDEX(displayIndex, -1);
   737 
   738     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   739 }
   740 
   741 int
   742 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   743 {
   744     SDL_VideoDisplay *display;
   745 
   746     CHECK_DISPLAY_INDEX(displayIndex, -1);
   747 
   748     display = &_this->displays[displayIndex];
   749     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   750         return SDL_SetError("index must be in the range of 0 - %d",
   751                             SDL_GetNumDisplayModesForDisplay(display) - 1);
   752     }
   753     if (mode) {
   754         *mode = display->display_modes[index];
   755     }
   756     return 0;
   757 }
   758 
   759 int
   760 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   761 {
   762     SDL_VideoDisplay *display;
   763 
   764     CHECK_DISPLAY_INDEX(displayIndex, -1);
   765 
   766     display = &_this->displays[displayIndex];
   767     if (mode) {
   768         *mode = display->desktop_mode;
   769     }
   770     return 0;
   771 }
   772 
   773 int
   774 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   775 {
   776     SDL_VideoDisplay *display;
   777 
   778     CHECK_DISPLAY_INDEX(displayIndex, -1);
   779 
   780     display = &_this->displays[displayIndex];
   781     if (mode) {
   782         *mode = display->current_mode;
   783     }
   784     return 0;
   785 }
   786 
   787 static SDL_DisplayMode *
   788 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   789                                     const SDL_DisplayMode * mode,
   790                                     SDL_DisplayMode * closest)
   791 {
   792     Uint32 target_format;
   793     int target_refresh_rate;
   794     int i;
   795     SDL_DisplayMode *current, *match;
   796 
   797     if (!mode || !closest) {
   798         SDL_SetError("Missing desired mode or closest mode parameter");
   799         return NULL;
   800     }
   801 
   802     /* Default to the desktop format */
   803     if (mode->format) {
   804         target_format = mode->format;
   805     } else {
   806         target_format = display->desktop_mode.format;
   807     }
   808 
   809     /* Default to the desktop refresh rate */
   810     if (mode->refresh_rate) {
   811         target_refresh_rate = mode->refresh_rate;
   812     } else {
   813         target_refresh_rate = display->desktop_mode.refresh_rate;
   814     }
   815 
   816     match = NULL;
   817     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   818         current = &display->display_modes[i];
   819 
   820         if (current->w && (current->w < mode->w)) {
   821             /* Out of sorted modes large enough here */
   822             break;
   823         }
   824         if (current->h && (current->h < mode->h)) {
   825             if (current->w && (current->w == mode->w)) {
   826                 /* Out of sorted modes large enough here */
   827                 break;
   828             }
   829             /* Wider, but not tall enough, due to a different
   830                aspect ratio. This mode must be skipped, but closer
   831                modes may still follow. */
   832             continue;
   833         }
   834         if (!match || current->w < match->w || current->h < match->h) {
   835             match = current;
   836             continue;
   837         }
   838         if (current->format != match->format) {
   839             /* Sorted highest depth to lowest */
   840             if (current->format == target_format ||
   841                 (SDL_BITSPERPIXEL(current->format) >=
   842                  SDL_BITSPERPIXEL(target_format)
   843                  && SDL_PIXELTYPE(current->format) ==
   844                  SDL_PIXELTYPE(target_format))) {
   845                 match = current;
   846             }
   847             continue;
   848         }
   849         if (current->refresh_rate != match->refresh_rate) {
   850             /* Sorted highest refresh to lowest */
   851             if (current->refresh_rate >= target_refresh_rate) {
   852                 match = current;
   853             }
   854         }
   855     }
   856     if (match) {
   857         if (match->format) {
   858             closest->format = match->format;
   859         } else {
   860             closest->format = mode->format;
   861         }
   862         if (match->w && match->h) {
   863             closest->w = match->w;
   864             closest->h = match->h;
   865         } else {
   866             closest->w = mode->w;
   867             closest->h = mode->h;
   868         }
   869         if (match->refresh_rate) {
   870             closest->refresh_rate = match->refresh_rate;
   871         } else {
   872             closest->refresh_rate = mode->refresh_rate;
   873         }
   874         closest->driverdata = match->driverdata;
   875 
   876         /*
   877          * Pick some reasonable defaults if the app and driver don't
   878          * care
   879          */
   880         if (!closest->format) {
   881             closest->format = SDL_PIXELFORMAT_RGB888;
   882         }
   883         if (!closest->w) {
   884             closest->w = 640;
   885         }
   886         if (!closest->h) {
   887             closest->h = 480;
   888         }
   889         return closest;
   890     }
   891     return NULL;
   892 }
   893 
   894 SDL_DisplayMode *
   895 SDL_GetClosestDisplayMode(int displayIndex,
   896                           const SDL_DisplayMode * mode,
   897                           SDL_DisplayMode * closest)
   898 {
   899     SDL_VideoDisplay *display;
   900 
   901     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   902 
   903     display = &_this->displays[displayIndex];
   904     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   905 }
   906 
   907 static int
   908 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   909 {
   910     SDL_DisplayMode display_mode;
   911     SDL_DisplayMode current_mode;
   912 
   913     if (mode) {
   914         display_mode = *mode;
   915 
   916         /* Default to the current mode */
   917         if (!display_mode.format) {
   918             display_mode.format = display->current_mode.format;
   919         }
   920         if (!display_mode.w) {
   921             display_mode.w = display->current_mode.w;
   922         }
   923         if (!display_mode.h) {
   924             display_mode.h = display->current_mode.h;
   925         }
   926         if (!display_mode.refresh_rate) {
   927             display_mode.refresh_rate = display->current_mode.refresh_rate;
   928         }
   929 
   930         /* Get a good video mode, the closest one possible */
   931         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   932             return SDL_SetError("No video mode large enough for %dx%d",
   933                                 display_mode.w, display_mode.h);
   934         }
   935     } else {
   936         display_mode = display->desktop_mode;
   937     }
   938 
   939     /* See if there's anything left to do */
   940     current_mode = display->current_mode;
   941     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   942         return 0;
   943     }
   944 
   945     /* Actually change the display mode */
   946     if (!_this->SetDisplayMode) {
   947         return SDL_SetError("Video driver doesn't support changing display mode");
   948     }
   949     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   950         return -1;
   951     }
   952     display->current_mode = display_mode;
   953     return 0;
   954 }
   955 
   956 int
   957 SDL_GetWindowDisplayIndex(SDL_Window * window)
   958 {
   959     int displayIndex;
   960     int i, dist;
   961     int closest = -1;
   962     int closest_dist = 0x7FFFFFFF;
   963     SDL_Point center;
   964     SDL_Point delta;
   965     SDL_Rect rect;
   966 
   967     CHECK_WINDOW_MAGIC(window, -1);
   968 
   969     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   970         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   971         displayIndex = (window->x & 0xFFFF);
   972         if (displayIndex >= _this->num_displays) {
   973             displayIndex = 0;
   974         }
   975         return displayIndex;
   976     }
   977     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   978         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   979         displayIndex = (window->y & 0xFFFF);
   980         if (displayIndex >= _this->num_displays) {
   981             displayIndex = 0;
   982         }
   983         return displayIndex;
   984     }
   985 
   986     /* Find the display containing the window */
   987     for (i = 0; i < _this->num_displays; ++i) {
   988         SDL_VideoDisplay *display = &_this->displays[i];
   989 
   990         if (display->fullscreen_window == window) {
   991             return i;
   992         }
   993     }
   994     center.x = window->x + window->w / 2;
   995     center.y = window->y + window->h / 2;
   996     for (i = 0; i < _this->num_displays; ++i) {
   997         SDL_GetDisplayBounds(i, &rect);
   998         if (SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   999             return i;
  1000         }
  1001 
  1002         delta.x = center.x - (rect.x + rect.w / 2);
  1003         delta.y = center.y - (rect.y + rect.h / 2);
  1004         dist = (delta.x*delta.x + delta.y*delta.y);
  1005         if (dist < closest_dist) {
  1006             closest = i;
  1007             closest_dist = dist;
  1008         }
  1009     }
  1010     if (closest < 0) {
  1011         SDL_SetError("Couldn't find any displays");
  1012     }
  1013     return closest;
  1014 }
  1015 
  1016 SDL_VideoDisplay *
  1017 SDL_GetDisplayForWindow(SDL_Window *window)
  1018 {
  1019     int displayIndex = SDL_GetWindowDisplayIndex(window);
  1020     if (displayIndex >= 0) {
  1021         return &_this->displays[displayIndex];
  1022     } else {
  1023         return NULL;
  1024     }
  1025 }
  1026 
  1027 int
  1028 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
  1029 {
  1030     CHECK_WINDOW_MAGIC(window, -1);
  1031 
  1032     if (mode) {
  1033         window->fullscreen_mode = *mode;
  1034     } else {
  1035         SDL_zero(window->fullscreen_mode);
  1036     }
  1037 
  1038     if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1039         SDL_DisplayMode fullscreen_mode;
  1040         if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
  1041             SDL_SetDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode);
  1042         }
  1043     }
  1044     return 0;
  1045 }
  1046 
  1047 int
  1048 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
  1049 {
  1050     SDL_DisplayMode fullscreen_mode;
  1051     SDL_VideoDisplay *display;
  1052 
  1053     CHECK_WINDOW_MAGIC(window, -1);
  1054 
  1055     if (!mode) {
  1056         return SDL_InvalidParamError("mode");
  1057     }
  1058 
  1059     fullscreen_mode = window->fullscreen_mode;
  1060     if (!fullscreen_mode.w) {
  1061         fullscreen_mode.w = window->windowed.w;
  1062     }
  1063     if (!fullscreen_mode.h) {
  1064         fullscreen_mode.h = window->windowed.h;
  1065     }
  1066 
  1067     display = SDL_GetDisplayForWindow(window);
  1068 
  1069     /* if in desktop size mode, just return the size of the desktop */
  1070     if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1071         fullscreen_mode = display->desktop_mode;
  1072     } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
  1073                                              &fullscreen_mode,
  1074                                              &fullscreen_mode)) {
  1075         return SDL_SetError("Couldn't find display mode match");
  1076     }
  1077 
  1078     if (mode) {
  1079         *mode = fullscreen_mode;
  1080     }
  1081     return 0;
  1082 }
  1083 
  1084 Uint32
  1085 SDL_GetWindowPixelFormat(SDL_Window * window)
  1086 {
  1087     SDL_VideoDisplay *display;
  1088 
  1089     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1090 
  1091     display = SDL_GetDisplayForWindow(window);
  1092     return display->current_mode.format;
  1093 }
  1094 
  1095 static void
  1096 SDL_RestoreMousePosition(SDL_Window *window)
  1097 {
  1098     int x, y;
  1099 
  1100     if (window == SDL_GetMouseFocus()) {
  1101         SDL_GetMouseState(&x, &y);
  1102         SDL_WarpMouseInWindow(window, x, y);
  1103     }
  1104 }
  1105 
  1106 static void
  1107 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1108 {
  1109     SDL_VideoDisplay *display;
  1110     SDL_Window *other;
  1111 
  1112     CHECK_WINDOW_MAGIC(window,);
  1113 
  1114     /* if we are in the process of hiding don't go back to fullscreen */
  1115     if ( window->is_hiding && fullscreen )
  1116         return;
  1117     
  1118 #ifdef __MACOSX__
  1119     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
  1120         window->last_fullscreen_flags = window->flags;
  1121         return;
  1122     }
  1123 #endif
  1124 
  1125     display = SDL_GetDisplayForWindow(window);
  1126 
  1127     if (fullscreen) {
  1128         /* Hide any other fullscreen windows */
  1129         if (display->fullscreen_window &&
  1130             display->fullscreen_window != window) {
  1131             SDL_MinimizeWindow(display->fullscreen_window);
  1132         }
  1133     }
  1134 
  1135     /* See if anything needs to be done now */
  1136     if ((display->fullscreen_window == window) == fullscreen) {
  1137         if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
  1138             return;
  1139         }
  1140     }
  1141 
  1142     /* See if there are any fullscreen windows */
  1143     for (other = _this->windows; other; other = other->next) {
  1144         SDL_bool setDisplayMode = SDL_FALSE;
  1145 
  1146         if (other == window) {
  1147             setDisplayMode = fullscreen;
  1148         } else if (FULLSCREEN_VISIBLE(other) &&
  1149                    SDL_GetDisplayForWindow(other) == display) {
  1150             setDisplayMode = SDL_TRUE;
  1151         }
  1152 
  1153         if (setDisplayMode) {
  1154             SDL_DisplayMode fullscreen_mode;
  1155 
  1156             SDL_zero(fullscreen_mode);
  1157 
  1158             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1159                 SDL_bool resized = SDL_TRUE;
  1160 
  1161                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1162                     resized = SDL_FALSE;
  1163                 }
  1164 
  1165                 /* only do the mode change if we want exclusive fullscreen */
  1166                 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1167                     SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1168                 } else {
  1169                     SDL_SetDisplayModeForDisplay(display, NULL);
  1170                 }
  1171 
  1172                 if (_this->SetWindowFullscreen) {
  1173                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1174                 }
  1175                 display->fullscreen_window = other;
  1176 
  1177                 /* Generate a mode change event here */
  1178                 if (resized) {
  1179                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1180                                         fullscreen_mode.w, fullscreen_mode.h);
  1181                 } else {
  1182                     SDL_OnWindowResized(other);
  1183                 }
  1184 
  1185                 SDL_RestoreMousePosition(other);
  1186 
  1187                 window->last_fullscreen_flags = window->flags;
  1188                 return;
  1189             }
  1190         }
  1191     }
  1192 
  1193     /* Nope, restore the desktop mode */
  1194     SDL_SetDisplayModeForDisplay(display, NULL);
  1195 
  1196     if (_this->SetWindowFullscreen) {
  1197         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1198     }
  1199     display->fullscreen_window = NULL;
  1200 
  1201     /* Generate a mode change event here */
  1202     SDL_OnWindowResized(window);
  1203 
  1204     /* Restore the cursor position */
  1205     SDL_RestoreMousePosition(window);
  1206 
  1207     window->last_fullscreen_flags = window->flags;
  1208 }
  1209 
  1210 #define CREATE_FLAGS \
  1211     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
  1212 
  1213 static void
  1214 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1215 {
  1216     window->windowed.x = window->x;
  1217     window->windowed.y = window->y;
  1218     window->windowed.w = window->w;
  1219     window->windowed.h = window->h;
  1220 
  1221     if (flags & SDL_WINDOW_MAXIMIZED) {
  1222         SDL_MaximizeWindow(window);
  1223     }
  1224     if (flags & SDL_WINDOW_MINIMIZED) {
  1225         SDL_MinimizeWindow(window);
  1226     }
  1227     if (flags & SDL_WINDOW_FULLSCREEN) {
  1228         SDL_SetWindowFullscreen(window, flags);
  1229     }
  1230     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1231         SDL_SetWindowGrab(window, SDL_TRUE);
  1232     }
  1233     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1234         SDL_ShowWindow(window);
  1235     }
  1236 }
  1237 
  1238 SDL_Window *
  1239 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1240 {
  1241     SDL_Window *window;
  1242     const char *hint;
  1243 
  1244     if (!_this) {
  1245         /* Initialize the video system if needed */
  1246         if (SDL_VideoInit(NULL) < 0) {
  1247             return NULL;
  1248         }
  1249     }
  1250 
  1251     /* Some platforms can't create zero-sized windows */
  1252     if (w < 1) {
  1253         w = 1;
  1254     }
  1255     if (h < 1) {
  1256         h = 1;
  1257     }
  1258 
  1259     /* Some platforms have OpenGL enabled by default */
  1260 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
  1261     flags |= SDL_WINDOW_OPENGL;
  1262 #endif
  1263     if (flags & SDL_WINDOW_OPENGL) {
  1264         if (!_this->GL_CreateContext) {
  1265             SDL_SetError("No OpenGL support in video driver");
  1266             return NULL;
  1267         }
  1268         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1269             return NULL;
  1270         }
  1271     }
  1272 
  1273     /* Unless the user has specified the high-DPI disabling hint, respect the
  1274      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1275      */
  1276     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1277         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1278         if (hint && SDL_atoi(hint) > 0) {
  1279             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1280         }
  1281     }
  1282 
  1283     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1284     if (!window) {
  1285         SDL_OutOfMemory();
  1286         return NULL;
  1287     }
  1288     window->magic = &_this->window_magic;
  1289     window->id = _this->next_object_id++;
  1290     window->x = x;
  1291     window->y = y;
  1292     window->w = w;
  1293     window->h = h;
  1294     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1295         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1296         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1297         int displayIndex;
  1298         SDL_Rect bounds;
  1299 
  1300         displayIndex = SDL_GetIndexOfDisplay(display);
  1301         SDL_GetDisplayBounds(displayIndex, &bounds);
  1302         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1303             window->x = bounds.x + (bounds.w - w) / 2;
  1304         }
  1305         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1306             window->y = bounds.y + (bounds.h - h) / 2;
  1307         }
  1308     }
  1309     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1310     window->last_fullscreen_flags = window->flags;
  1311     window->brightness = 1.0f;
  1312     window->next = _this->windows;
  1313     window->is_destroying = SDL_FALSE;
  1314 
  1315     if (_this->windows) {
  1316         _this->windows->prev = window;
  1317     }
  1318     _this->windows = window;
  1319 
  1320     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1321         SDL_DestroyWindow(window);
  1322         return NULL;
  1323     }
  1324 
  1325     if (title) {
  1326         SDL_SetWindowTitle(window, title);
  1327     }
  1328     SDL_FinishWindowCreation(window, flags);
  1329 
  1330     /* If the window was created fullscreen, make sure the mode code matches */
  1331     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1332 
  1333     return window;
  1334 }
  1335 
  1336 SDL_Window *
  1337 SDL_CreateWindowFrom(const void *data)
  1338 {
  1339     SDL_Window *window;
  1340 
  1341     if (!_this) {
  1342         SDL_UninitializedVideo();
  1343         return NULL;
  1344     }
  1345     if (!_this->CreateWindowFrom) {
  1346         SDL_Unsupported();
  1347         return NULL;
  1348     }
  1349     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1350     if (!window) {
  1351         SDL_OutOfMemory();
  1352         return NULL;
  1353     }
  1354     window->magic = &_this->window_magic;
  1355     window->id = _this->next_object_id++;
  1356     window->flags = SDL_WINDOW_FOREIGN;
  1357     window->last_fullscreen_flags = window->flags;
  1358     window->is_destroying = SDL_FALSE;
  1359     window->brightness = 1.0f;
  1360     window->next = _this->windows;
  1361     if (_this->windows) {
  1362         _this->windows->prev = window;
  1363     }
  1364     _this->windows = window;
  1365 
  1366     if (_this->CreateWindowFrom(_this, window, data) < 0) {
  1367         SDL_DestroyWindow(window);
  1368         return NULL;
  1369     }
  1370     return window;
  1371 }
  1372 
  1373 int
  1374 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1375 {
  1376     char *title = window->title;
  1377     SDL_Surface *icon = window->icon;
  1378     SDL_bool loaded_opengl = SDL_FALSE;
  1379 
  1380     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1381         return SDL_SetError("No OpenGL support in video driver");
  1382     }
  1383 
  1384     if (window->flags & SDL_WINDOW_FOREIGN) {
  1385         /* Can't destroy and re-create foreign windows, hrm */
  1386         flags |= SDL_WINDOW_FOREIGN;
  1387     } else {
  1388         flags &= ~SDL_WINDOW_FOREIGN;
  1389     }
  1390 
  1391     /* Restore video mode, etc. */
  1392     SDL_HideWindow(window);
  1393 
  1394     /* Tear down the old native window */
  1395     if (window->surface) {
  1396         window->surface->flags &= ~SDL_DONTFREE;
  1397         SDL_FreeSurface(window->surface);
  1398     }
  1399     if (_this->DestroyWindowFramebuffer) {
  1400         _this->DestroyWindowFramebuffer(_this, window);
  1401     }
  1402     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1403         _this->DestroyWindow(_this, window);
  1404     }
  1405 
  1406     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1407         if (flags & SDL_WINDOW_OPENGL) {
  1408             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1409                 return -1;
  1410             }
  1411             loaded_opengl = SDL_TRUE;
  1412         } else {
  1413             SDL_GL_UnloadLibrary();
  1414         }
  1415     }
  1416 
  1417     window->title = NULL;
  1418     window->icon = NULL;
  1419     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1420     window->last_fullscreen_flags = window->flags;
  1421     window->is_destroying = SDL_FALSE;
  1422 
  1423     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1424         if (_this->CreateWindow(_this, window) < 0) {
  1425             if (loaded_opengl) {
  1426                 SDL_GL_UnloadLibrary();
  1427                 window->flags &= ~SDL_WINDOW_OPENGL;
  1428             }
  1429             return -1;
  1430         }
  1431     }
  1432     if (flags & SDL_WINDOW_FOREIGN) {
  1433         window->flags |= SDL_WINDOW_FOREIGN;
  1434     }
  1435 
  1436     if (title) {
  1437         SDL_SetWindowTitle(window, title);
  1438         SDL_free(title);
  1439     }
  1440     if (icon) {
  1441         SDL_SetWindowIcon(window, icon);
  1442         SDL_FreeSurface(icon);
  1443     }
  1444 
  1445     if (window->hit_test) {
  1446         _this->SetWindowHitTest(window, SDL_TRUE);
  1447     }
  1448 
  1449     SDL_FinishWindowCreation(window, flags);
  1450 
  1451     return 0;
  1452 }
  1453 
  1454 Uint32
  1455 SDL_GetWindowID(SDL_Window * window)
  1456 {
  1457     CHECK_WINDOW_MAGIC(window, 0);
  1458 
  1459     return window->id;
  1460 }
  1461 
  1462 SDL_Window *
  1463 SDL_GetWindowFromID(Uint32 id)
  1464 {
  1465     SDL_Window *window;
  1466 
  1467     if (!_this) {
  1468         return NULL;
  1469     }
  1470     for (window = _this->windows; window; window = window->next) {
  1471         if (window->id == id) {
  1472             return window;
  1473         }
  1474     }
  1475     return NULL;
  1476 }
  1477 
  1478 Uint32
  1479 SDL_GetWindowFlags(SDL_Window * window)
  1480 {
  1481     CHECK_WINDOW_MAGIC(window, 0);
  1482 
  1483     return window->flags;
  1484 }
  1485 
  1486 void
  1487 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1488 {
  1489     CHECK_WINDOW_MAGIC(window,);
  1490 
  1491     if (title == window->title) {
  1492         return;
  1493     }
  1494     SDL_free(window->title);
  1495     if (title && *title) {
  1496         window->title = SDL_strdup(title);
  1497     } else {
  1498         window->title = NULL;
  1499     }
  1500 
  1501     if (_this->SetWindowTitle) {
  1502         _this->SetWindowTitle(_this, window);
  1503     }
  1504 }
  1505 
  1506 const char *
  1507 SDL_GetWindowTitle(SDL_Window * window)
  1508 {
  1509     CHECK_WINDOW_MAGIC(window, "");
  1510 
  1511     return window->title ? window->title : "";
  1512 }
  1513 
  1514 void
  1515 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1516 {
  1517     CHECK_WINDOW_MAGIC(window,);
  1518 
  1519     if (!icon) {
  1520         return;
  1521     }
  1522 
  1523     SDL_FreeSurface(window->icon);
  1524 
  1525     /* Convert the icon into ARGB8888 */
  1526     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1527     if (!window->icon) {
  1528         return;
  1529     }
  1530 
  1531     if (_this->SetWindowIcon) {
  1532         _this->SetWindowIcon(_this, window, window->icon);
  1533     }
  1534 }
  1535 
  1536 void*
  1537 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1538 {
  1539     SDL_WindowUserData *prev, *data;
  1540 
  1541     CHECK_WINDOW_MAGIC(window, NULL);
  1542 
  1543     /* Input validation */
  1544     if (name == NULL || name[0] == '\0') {
  1545       SDL_InvalidParamError("name");
  1546       return NULL;
  1547     }
  1548 
  1549     /* See if the named data already exists */
  1550     prev = NULL;
  1551     for (data = window->data; data; prev = data, data = data->next) {
  1552         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1553             void *last_value = data->data;
  1554 
  1555             if (userdata) {
  1556                 /* Set the new value */
  1557                 data->data = userdata;
  1558             } else {
  1559                 /* Delete this value */
  1560                 if (prev) {
  1561                     prev->next = data->next;
  1562                 } else {
  1563                     window->data = data->next;
  1564                 }
  1565                 SDL_free(data->name);
  1566                 SDL_free(data);
  1567             }
  1568             return last_value;
  1569         }
  1570     }
  1571 
  1572     /* Add new data to the window */
  1573     if (userdata) {
  1574         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1575         data->name = SDL_strdup(name);
  1576         data->data = userdata;
  1577         data->next = window->data;
  1578         window->data = data;
  1579     }
  1580     return NULL;
  1581 }
  1582 
  1583 void *
  1584 SDL_GetWindowData(SDL_Window * window, const char *name)
  1585 {
  1586     SDL_WindowUserData *data;
  1587 
  1588     CHECK_WINDOW_MAGIC(window, NULL);
  1589 
  1590     /* Input validation */
  1591     if (name == NULL || name[0] == '\0') {
  1592       SDL_InvalidParamError("name");
  1593       return NULL;
  1594     }
  1595 
  1596     for (data = window->data; data; data = data->next) {
  1597         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1598             return data->data;
  1599         }
  1600     }
  1601     return NULL;
  1602 }
  1603 
  1604 void
  1605 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1606 {
  1607     CHECK_WINDOW_MAGIC(window,);
  1608 
  1609     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1610         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1611         int displayIndex;
  1612         SDL_Rect bounds;
  1613 
  1614         SDL_zero(bounds);
  1615 
  1616         displayIndex = SDL_GetIndexOfDisplay(display);
  1617         SDL_GetDisplayBounds(displayIndex, &bounds);
  1618         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1619             x = bounds.x + (bounds.w - window->w) / 2;
  1620         }
  1621         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1622             y = bounds.y + (bounds.h - window->h) / 2;
  1623         }
  1624     }
  1625 
  1626     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1627         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1628             window->windowed.x = x;
  1629         }
  1630         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1631             window->windowed.y = y;
  1632         }
  1633     } else {
  1634         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1635             window->x = x;
  1636         }
  1637         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1638             window->y = y;
  1639         }
  1640 
  1641         if (_this->SetWindowPosition) {
  1642             _this->SetWindowPosition(_this, window);
  1643         }
  1644         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1645     }
  1646 }
  1647 
  1648 void
  1649 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1650 {
  1651     CHECK_WINDOW_MAGIC(window,);
  1652 
  1653     /* Fullscreen windows are always at their display's origin */
  1654     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1655         if (x) {
  1656             *x = 0;
  1657         }
  1658         if (y) {
  1659             *y = 0;
  1660         }
  1661     } else {
  1662         if (x) {
  1663             *x = window->x;
  1664         }
  1665         if (y) {
  1666             *y = window->y;
  1667         }
  1668     }
  1669 }
  1670 
  1671 void
  1672 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1673 {
  1674     CHECK_WINDOW_MAGIC(window,);
  1675     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1676         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1677         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1678         if ((want != have) && (_this->SetWindowBordered)) {
  1679             if (want) {
  1680                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1681             } else {
  1682                 window->flags |= SDL_WINDOW_BORDERLESS;
  1683             }
  1684             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1685         }
  1686     }
  1687 }
  1688 
  1689 void
  1690 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1691 {
  1692     CHECK_WINDOW_MAGIC(window,);
  1693     if (w <= 0) {
  1694         SDL_InvalidParamError("w");
  1695         return;
  1696     }
  1697     if (h <= 0) {
  1698         SDL_InvalidParamError("h");
  1699         return;
  1700     }
  1701 
  1702     /* Make sure we don't exceed any window size limits */
  1703     if (window->min_w && w < window->min_w)
  1704     {
  1705         w = window->min_w;
  1706     }
  1707     if (window->max_w && w > window->max_w)
  1708     {
  1709         w = window->max_w;
  1710     }
  1711     if (window->min_h && h < window->min_h)
  1712     {
  1713         h = window->min_h;
  1714     }
  1715     if (window->max_h && h > window->max_h)
  1716     {
  1717         h = window->max_h;
  1718     }
  1719 
  1720     window->windowed.w = w;
  1721     window->windowed.h = h;
  1722 
  1723     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1724         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1725             window->last_fullscreen_flags = 0;
  1726             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1727         }
  1728     } else {
  1729         window->w = w;
  1730         window->h = h;
  1731         if (_this->SetWindowSize) {
  1732             _this->SetWindowSize(_this, window);
  1733         }
  1734         if (window->w == w && window->h == h) {
  1735             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1736             SDL_OnWindowResized(window);
  1737         }
  1738     }
  1739 }
  1740 
  1741 void
  1742 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1743 {
  1744     CHECK_WINDOW_MAGIC(window,);
  1745     if (w) {
  1746         *w = window->w;
  1747     }
  1748     if (h) {
  1749         *h = window->h;
  1750     }
  1751 }
  1752 
  1753 void
  1754 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1755 {
  1756     CHECK_WINDOW_MAGIC(window,);
  1757     if (min_w <= 0) {
  1758         SDL_InvalidParamError("min_w");
  1759         return;
  1760     }
  1761     if (min_h <= 0) {
  1762         SDL_InvalidParamError("min_h");
  1763         return;
  1764     }
  1765 
  1766     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1767         window->min_w = min_w;
  1768         window->min_h = min_h;
  1769         if (_this->SetWindowMinimumSize) {
  1770             _this->SetWindowMinimumSize(_this, window);
  1771         }
  1772         /* Ensure that window is not smaller than minimal size */
  1773         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1774     }
  1775 }
  1776 
  1777 void
  1778 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1779 {
  1780     CHECK_WINDOW_MAGIC(window,);
  1781     if (min_w) {
  1782         *min_w = window->min_w;
  1783     }
  1784     if (min_h) {
  1785         *min_h = window->min_h;
  1786     }
  1787 }
  1788 
  1789 void
  1790 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1791 {
  1792     CHECK_WINDOW_MAGIC(window,);
  1793     if (max_w <= 0) {
  1794         SDL_InvalidParamError("max_w");
  1795         return;
  1796     }
  1797     if (max_h <= 0) {
  1798         SDL_InvalidParamError("max_h");
  1799         return;
  1800     }
  1801 
  1802     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1803         window->max_w = max_w;
  1804         window->max_h = max_h;
  1805         if (_this->SetWindowMaximumSize) {
  1806             _this->SetWindowMaximumSize(_this, window);
  1807         }
  1808         /* Ensure that window is not larger than maximal size */
  1809         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1810     }
  1811 }
  1812 
  1813 void
  1814 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1815 {
  1816     CHECK_WINDOW_MAGIC(window,);
  1817     if (max_w) {
  1818         *max_w = window->max_w;
  1819     }
  1820     if (max_h) {
  1821         *max_h = window->max_h;
  1822     }
  1823 }
  1824 
  1825 void
  1826 SDL_ShowWindow(SDL_Window * window)
  1827 {
  1828     CHECK_WINDOW_MAGIC(window,);
  1829 
  1830     if (window->flags & SDL_WINDOW_SHOWN) {
  1831         return;
  1832     }
  1833 
  1834     if (_this->ShowWindow) {
  1835         _this->ShowWindow(_this, window);
  1836     }
  1837     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1838 }
  1839 
  1840 void
  1841 SDL_HideWindow(SDL_Window * window)
  1842 {
  1843     CHECK_WINDOW_MAGIC(window,);
  1844 
  1845     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1846         return;
  1847     }
  1848 
  1849 	window->is_hiding = SDL_TRUE;
  1850     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1851 
  1852     if (_this->HideWindow) {
  1853         _this->HideWindow(_this, window);
  1854     }
  1855 	window->is_hiding = SDL_FALSE;
  1856     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1857 }
  1858 
  1859 void
  1860 SDL_RaiseWindow(SDL_Window * window)
  1861 {
  1862     CHECK_WINDOW_MAGIC(window,);
  1863 
  1864     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1865         return;
  1866     }
  1867     if (_this->RaiseWindow) {
  1868         _this->RaiseWindow(_this, window);
  1869     }
  1870 }
  1871 
  1872 void
  1873 SDL_MaximizeWindow(SDL_Window * window)
  1874 {
  1875     CHECK_WINDOW_MAGIC(window,);
  1876 
  1877     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1878         return;
  1879     }
  1880 
  1881     /* !!! FIXME: should this check if the window is resizable? */
  1882 
  1883     if (_this->MaximizeWindow) {
  1884         _this->MaximizeWindow(_this, window);
  1885     }
  1886 }
  1887 
  1888 void
  1889 SDL_MinimizeWindow(SDL_Window * window)
  1890 {
  1891     CHECK_WINDOW_MAGIC(window,);
  1892 
  1893     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1894         return;
  1895     }
  1896 
  1897     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1898 
  1899     if (_this->MinimizeWindow) {
  1900         _this->MinimizeWindow(_this, window);
  1901     }
  1902 }
  1903 
  1904 void
  1905 SDL_RestoreWindow(SDL_Window * window)
  1906 {
  1907     CHECK_WINDOW_MAGIC(window,);
  1908 
  1909     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1910         return;
  1911     }
  1912 
  1913     if (_this->RestoreWindow) {
  1914         _this->RestoreWindow(_this, window);
  1915     }
  1916 }
  1917 
  1918 int
  1919 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1920 {
  1921     CHECK_WINDOW_MAGIC(window, -1);
  1922 
  1923     flags &= FULLSCREEN_MASK;
  1924 
  1925     if (flags == (window->flags & FULLSCREEN_MASK)) {
  1926         return 0;
  1927     }
  1928 
  1929     /* clear the previous flags and OR in the new ones */
  1930     window->flags &= ~FULLSCREEN_MASK;
  1931     window->flags |= flags;
  1932 
  1933     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1934 
  1935     return 0;
  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: */