src/video/SDL_video.c
author Alex Szpakowski <slime73@gmail.com>
Thu, 15 Jan 2015 01:15:24 -0400
branchiOS-improvements
changeset 9533 e5693e855338
parent 9532 318042c16b76
parent 9278 8900afb78a19
child 9536 3c87b8f9dc58
permissions -rw-r--r--
Merged default into iOS-improvements
     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 int
  1107 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1108 {
  1109     SDL_VideoDisplay *display;
  1110     SDL_Window *other;
  1111 
  1112     CHECK_WINDOW_MAGIC(window,-1);
  1113 
  1114     /* if we are in the process of hiding don't go back to fullscreen */
  1115     if ( window->is_hiding && fullscreen )
  1116         return 0;
  1117     
  1118 #ifdef __MACOSX__
  1119     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
  1120         window->last_fullscreen_flags = window->flags;
  1121         return 0;
  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 0;
  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                     if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
  1168                         return -1;
  1169                     }
  1170                 } else {
  1171                     if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
  1172                         return -1;
  1173                     }
  1174                 }
  1175 
  1176                 if (_this->SetWindowFullscreen) {
  1177                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1178                 }
  1179                 display->fullscreen_window = other;
  1180 
  1181                 /* Generate a mode change event here */
  1182                 if (resized) {
  1183                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1184                                         fullscreen_mode.w, fullscreen_mode.h);
  1185                 } else {
  1186                     SDL_OnWindowResized(other);
  1187                 }
  1188 
  1189                 SDL_RestoreMousePosition(other);
  1190 
  1191                 window->last_fullscreen_flags = window->flags;
  1192                 return 0;
  1193             }
  1194         }
  1195     }
  1196 
  1197     /* Nope, restore the desktop mode */
  1198     SDL_SetDisplayModeForDisplay(display, NULL);
  1199 
  1200     if (_this->SetWindowFullscreen) {
  1201         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1202     }
  1203     display->fullscreen_window = NULL;
  1204 
  1205     /* Generate a mode change event here */
  1206     SDL_OnWindowResized(window);
  1207 
  1208     /* Restore the cursor position */
  1209     SDL_RestoreMousePosition(window);
  1210 
  1211     window->last_fullscreen_flags = window->flags;
  1212     return 0;
  1213 }
  1214 
  1215 #define CREATE_FLAGS \
  1216     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
  1217 
  1218 static void
  1219 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1220 {
  1221     window->windowed.x = window->x;
  1222     window->windowed.y = window->y;
  1223     window->windowed.w = window->w;
  1224     window->windowed.h = window->h;
  1225 
  1226     if (flags & SDL_WINDOW_MAXIMIZED) {
  1227         SDL_MaximizeWindow(window);
  1228     }
  1229     if (flags & SDL_WINDOW_MINIMIZED) {
  1230         SDL_MinimizeWindow(window);
  1231     }
  1232     if (flags & SDL_WINDOW_FULLSCREEN) {
  1233         SDL_SetWindowFullscreen(window, flags);
  1234     }
  1235     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1236         SDL_SetWindowGrab(window, SDL_TRUE);
  1237     }
  1238     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1239         SDL_ShowWindow(window);
  1240     }
  1241 }
  1242 
  1243 SDL_Window *
  1244 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1245 {
  1246     SDL_Window *window;
  1247     const char *hint;
  1248 
  1249     if (!_this) {
  1250         /* Initialize the video system if needed */
  1251         if (SDL_VideoInit(NULL) < 0) {
  1252             return NULL;
  1253         }
  1254     }
  1255 
  1256     /* Some platforms can't create zero-sized windows */
  1257     if (w < 1) {
  1258         w = 1;
  1259     }
  1260     if (h < 1) {
  1261         h = 1;
  1262     }
  1263 
  1264     /* Some platforms have OpenGL enabled by default */
  1265 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
  1266     flags |= SDL_WINDOW_OPENGL;
  1267 #endif
  1268     if (flags & SDL_WINDOW_OPENGL) {
  1269         if (!_this->GL_CreateContext) {
  1270             SDL_SetError("No OpenGL support in video driver");
  1271             return NULL;
  1272         }
  1273         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1274             return NULL;
  1275         }
  1276     }
  1277 
  1278     /* Unless the user has specified the high-DPI disabling hint, respect the
  1279      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1280      */
  1281     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1282         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1283         if (hint && SDL_atoi(hint) > 0) {
  1284             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1285         }
  1286     }
  1287 
  1288     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1289     if (!window) {
  1290         SDL_OutOfMemory();
  1291         return NULL;
  1292     }
  1293     window->magic = &_this->window_magic;
  1294     window->id = _this->next_object_id++;
  1295     window->x = x;
  1296     window->y = y;
  1297     window->w = w;
  1298     window->h = h;
  1299     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1300         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1301         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1302         int displayIndex;
  1303         SDL_Rect bounds;
  1304 
  1305         displayIndex = SDL_GetIndexOfDisplay(display);
  1306         SDL_GetDisplayBounds(displayIndex, &bounds);
  1307         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1308             window->x = bounds.x + (bounds.w - w) / 2;
  1309         }
  1310         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1311             window->y = bounds.y + (bounds.h - h) / 2;
  1312         }
  1313     }
  1314     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1315     window->last_fullscreen_flags = window->flags;
  1316     window->brightness = 1.0f;
  1317     window->next = _this->windows;
  1318     window->is_destroying = SDL_FALSE;
  1319 
  1320     if (_this->windows) {
  1321         _this->windows->prev = window;
  1322     }
  1323     _this->windows = window;
  1324 
  1325     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1326         SDL_DestroyWindow(window);
  1327         return NULL;
  1328     }
  1329 
  1330     if (title) {
  1331         SDL_SetWindowTitle(window, title);
  1332     }
  1333     SDL_FinishWindowCreation(window, flags);
  1334 
  1335     /* If the window was created fullscreen, make sure the mode code matches */
  1336     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1337 
  1338     return window;
  1339 }
  1340 
  1341 SDL_Window *
  1342 SDL_CreateWindowFrom(const void *data)
  1343 {
  1344     SDL_Window *window;
  1345 
  1346     if (!_this) {
  1347         SDL_UninitializedVideo();
  1348         return NULL;
  1349     }
  1350     if (!_this->CreateWindowFrom) {
  1351         SDL_Unsupported();
  1352         return NULL;
  1353     }
  1354     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1355     if (!window) {
  1356         SDL_OutOfMemory();
  1357         return NULL;
  1358     }
  1359     window->magic = &_this->window_magic;
  1360     window->id = _this->next_object_id++;
  1361     window->flags = SDL_WINDOW_FOREIGN;
  1362     window->last_fullscreen_flags = window->flags;
  1363     window->is_destroying = SDL_FALSE;
  1364     window->brightness = 1.0f;
  1365     window->next = _this->windows;
  1366     if (_this->windows) {
  1367         _this->windows->prev = window;
  1368     }
  1369     _this->windows = window;
  1370 
  1371     if (_this->CreateWindowFrom(_this, window, data) < 0) {
  1372         SDL_DestroyWindow(window);
  1373         return NULL;
  1374     }
  1375     return window;
  1376 }
  1377 
  1378 int
  1379 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1380 {
  1381     char *title = window->title;
  1382     SDL_Surface *icon = window->icon;
  1383     SDL_bool loaded_opengl = SDL_FALSE;
  1384 
  1385     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1386         return SDL_SetError("No OpenGL support in video driver");
  1387     }
  1388 
  1389     if (window->flags & SDL_WINDOW_FOREIGN) {
  1390         /* Can't destroy and re-create foreign windows, hrm */
  1391         flags |= SDL_WINDOW_FOREIGN;
  1392     } else {
  1393         flags &= ~SDL_WINDOW_FOREIGN;
  1394     }
  1395 
  1396     /* Restore video mode, etc. */
  1397     SDL_HideWindow(window);
  1398 
  1399     /* Tear down the old native window */
  1400     if (window->surface) {
  1401         window->surface->flags &= ~SDL_DONTFREE;
  1402         SDL_FreeSurface(window->surface);
  1403     }
  1404     if (_this->DestroyWindowFramebuffer) {
  1405         _this->DestroyWindowFramebuffer(_this, window);
  1406     }
  1407     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1408         _this->DestroyWindow(_this, window);
  1409     }
  1410 
  1411     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1412         if (flags & SDL_WINDOW_OPENGL) {
  1413             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1414                 return -1;
  1415             }
  1416             loaded_opengl = SDL_TRUE;
  1417         } else {
  1418             SDL_GL_UnloadLibrary();
  1419         }
  1420     }
  1421 
  1422     window->title = NULL;
  1423     window->icon = NULL;
  1424     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1425     window->last_fullscreen_flags = window->flags;
  1426     window->is_destroying = SDL_FALSE;
  1427 
  1428     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1429         if (_this->CreateWindow(_this, window) < 0) {
  1430             if (loaded_opengl) {
  1431                 SDL_GL_UnloadLibrary();
  1432                 window->flags &= ~SDL_WINDOW_OPENGL;
  1433             }
  1434             return -1;
  1435         }
  1436     }
  1437     if (flags & SDL_WINDOW_FOREIGN) {
  1438         window->flags |= SDL_WINDOW_FOREIGN;
  1439     }
  1440 
  1441     if (title) {
  1442         SDL_SetWindowTitle(window, title);
  1443         SDL_free(title);
  1444     }
  1445     if (icon) {
  1446         SDL_SetWindowIcon(window, icon);
  1447         SDL_FreeSurface(icon);
  1448     }
  1449 
  1450     if (window->hit_test) {
  1451         _this->SetWindowHitTest(window, SDL_TRUE);
  1452     }
  1453 
  1454     SDL_FinishWindowCreation(window, flags);
  1455 
  1456     return 0;
  1457 }
  1458 
  1459 Uint32
  1460 SDL_GetWindowID(SDL_Window * window)
  1461 {
  1462     CHECK_WINDOW_MAGIC(window, 0);
  1463 
  1464     return window->id;
  1465 }
  1466 
  1467 SDL_Window *
  1468 SDL_GetWindowFromID(Uint32 id)
  1469 {
  1470     SDL_Window *window;
  1471 
  1472     if (!_this) {
  1473         return NULL;
  1474     }
  1475     for (window = _this->windows; window; window = window->next) {
  1476         if (window->id == id) {
  1477             return window;
  1478         }
  1479     }
  1480     return NULL;
  1481 }
  1482 
  1483 Uint32
  1484 SDL_GetWindowFlags(SDL_Window * window)
  1485 {
  1486     CHECK_WINDOW_MAGIC(window, 0);
  1487 
  1488     return window->flags;
  1489 }
  1490 
  1491 void
  1492 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1493 {
  1494     CHECK_WINDOW_MAGIC(window,);
  1495 
  1496     if (title == window->title) {
  1497         return;
  1498     }
  1499     SDL_free(window->title);
  1500     if (title && *title) {
  1501         window->title = SDL_strdup(title);
  1502     } else {
  1503         window->title = NULL;
  1504     }
  1505 
  1506     if (_this->SetWindowTitle) {
  1507         _this->SetWindowTitle(_this, window);
  1508     }
  1509 }
  1510 
  1511 const char *
  1512 SDL_GetWindowTitle(SDL_Window * window)
  1513 {
  1514     CHECK_WINDOW_MAGIC(window, "");
  1515 
  1516     return window->title ? window->title : "";
  1517 }
  1518 
  1519 void
  1520 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1521 {
  1522     CHECK_WINDOW_MAGIC(window,);
  1523 
  1524     if (!icon) {
  1525         return;
  1526     }
  1527 
  1528     SDL_FreeSurface(window->icon);
  1529 
  1530     /* Convert the icon into ARGB8888 */
  1531     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1532     if (!window->icon) {
  1533         return;
  1534     }
  1535 
  1536     if (_this->SetWindowIcon) {
  1537         _this->SetWindowIcon(_this, window, window->icon);
  1538     }
  1539 }
  1540 
  1541 void*
  1542 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1543 {
  1544     SDL_WindowUserData *prev, *data;
  1545 
  1546     CHECK_WINDOW_MAGIC(window, NULL);
  1547 
  1548     /* Input validation */
  1549     if (name == NULL || name[0] == '\0') {
  1550       SDL_InvalidParamError("name");
  1551       return NULL;
  1552     }
  1553 
  1554     /* See if the named data already exists */
  1555     prev = NULL;
  1556     for (data = window->data; data; prev = data, data = data->next) {
  1557         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1558             void *last_value = data->data;
  1559 
  1560             if (userdata) {
  1561                 /* Set the new value */
  1562                 data->data = userdata;
  1563             } else {
  1564                 /* Delete this value */
  1565                 if (prev) {
  1566                     prev->next = data->next;
  1567                 } else {
  1568                     window->data = data->next;
  1569                 }
  1570                 SDL_free(data->name);
  1571                 SDL_free(data);
  1572             }
  1573             return last_value;
  1574         }
  1575     }
  1576 
  1577     /* Add new data to the window */
  1578     if (userdata) {
  1579         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1580         data->name = SDL_strdup(name);
  1581         data->data = userdata;
  1582         data->next = window->data;
  1583         window->data = data;
  1584     }
  1585     return NULL;
  1586 }
  1587 
  1588 void *
  1589 SDL_GetWindowData(SDL_Window * window, const char *name)
  1590 {
  1591     SDL_WindowUserData *data;
  1592 
  1593     CHECK_WINDOW_MAGIC(window, NULL);
  1594 
  1595     /* Input validation */
  1596     if (name == NULL || name[0] == '\0') {
  1597       SDL_InvalidParamError("name");
  1598       return NULL;
  1599     }
  1600 
  1601     for (data = window->data; data; data = data->next) {
  1602         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1603             return data->data;
  1604         }
  1605     }
  1606     return NULL;
  1607 }
  1608 
  1609 void
  1610 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1611 {
  1612     CHECK_WINDOW_MAGIC(window,);
  1613 
  1614     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1615         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1616         int displayIndex;
  1617         SDL_Rect bounds;
  1618 
  1619         SDL_zero(bounds);
  1620 
  1621         displayIndex = SDL_GetIndexOfDisplay(display);
  1622         SDL_GetDisplayBounds(displayIndex, &bounds);
  1623         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1624             x = bounds.x + (bounds.w - window->w) / 2;
  1625         }
  1626         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1627             y = bounds.y + (bounds.h - window->h) / 2;
  1628         }
  1629     }
  1630 
  1631     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1632         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1633             window->windowed.x = x;
  1634         }
  1635         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1636             window->windowed.y = y;
  1637         }
  1638     } else {
  1639         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1640             window->x = x;
  1641         }
  1642         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1643             window->y = y;
  1644         }
  1645 
  1646         if (_this->SetWindowPosition) {
  1647             _this->SetWindowPosition(_this, window);
  1648         }
  1649         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1650     }
  1651 }
  1652 
  1653 void
  1654 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1655 {
  1656     CHECK_WINDOW_MAGIC(window,);
  1657 
  1658     /* Fullscreen windows are always at their display's origin */
  1659     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1660         if (x) {
  1661             *x = 0;
  1662         }
  1663         if (y) {
  1664             *y = 0;
  1665         }
  1666     } else {
  1667         if (x) {
  1668             *x = window->x;
  1669         }
  1670         if (y) {
  1671             *y = window->y;
  1672         }
  1673     }
  1674 }
  1675 
  1676 void
  1677 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1678 {
  1679     CHECK_WINDOW_MAGIC(window,);
  1680     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1681         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1682         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1683         if ((want != have) && (_this->SetWindowBordered)) {
  1684             if (want) {
  1685                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1686             } else {
  1687                 window->flags |= SDL_WINDOW_BORDERLESS;
  1688             }
  1689             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1690         }
  1691     }
  1692 }
  1693 
  1694 void
  1695 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1696 {
  1697     CHECK_WINDOW_MAGIC(window,);
  1698     if (w <= 0) {
  1699         SDL_InvalidParamError("w");
  1700         return;
  1701     }
  1702     if (h <= 0) {
  1703         SDL_InvalidParamError("h");
  1704         return;
  1705     }
  1706 
  1707     /* Make sure we don't exceed any window size limits */
  1708     if (window->min_w && w < window->min_w)
  1709     {
  1710         w = window->min_w;
  1711     }
  1712     if (window->max_w && w > window->max_w)
  1713     {
  1714         w = window->max_w;
  1715     }
  1716     if (window->min_h && h < window->min_h)
  1717     {
  1718         h = window->min_h;
  1719     }
  1720     if (window->max_h && h > window->max_h)
  1721     {
  1722         h = window->max_h;
  1723     }
  1724 
  1725     window->windowed.w = w;
  1726     window->windowed.h = h;
  1727 
  1728     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1729         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1730             window->last_fullscreen_flags = 0;
  1731             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1732         }
  1733     } else {
  1734         window->w = w;
  1735         window->h = h;
  1736         if (_this->SetWindowSize) {
  1737             _this->SetWindowSize(_this, window);
  1738         }
  1739         if (window->w == w && window->h == h) {
  1740             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1741             SDL_OnWindowResized(window);
  1742         }
  1743     }
  1744 }
  1745 
  1746 void
  1747 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1748 {
  1749     CHECK_WINDOW_MAGIC(window,);
  1750     if (w) {
  1751         *w = window->w;
  1752     }
  1753     if (h) {
  1754         *h = window->h;
  1755     }
  1756 }
  1757 
  1758 void
  1759 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1760 {
  1761     CHECK_WINDOW_MAGIC(window,);
  1762     if (min_w <= 0) {
  1763         SDL_InvalidParamError("min_w");
  1764         return;
  1765     }
  1766     if (min_h <= 0) {
  1767         SDL_InvalidParamError("min_h");
  1768         return;
  1769     }
  1770 
  1771     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1772         window->min_w = min_w;
  1773         window->min_h = min_h;
  1774         if (_this->SetWindowMinimumSize) {
  1775             _this->SetWindowMinimumSize(_this, window);
  1776         }
  1777         /* Ensure that window is not smaller than minimal size */
  1778         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1779     }
  1780 }
  1781 
  1782 void
  1783 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1784 {
  1785     CHECK_WINDOW_MAGIC(window,);
  1786     if (min_w) {
  1787         *min_w = window->min_w;
  1788     }
  1789     if (min_h) {
  1790         *min_h = window->min_h;
  1791     }
  1792 }
  1793 
  1794 void
  1795 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1796 {
  1797     CHECK_WINDOW_MAGIC(window,);
  1798     if (max_w <= 0) {
  1799         SDL_InvalidParamError("max_w");
  1800         return;
  1801     }
  1802     if (max_h <= 0) {
  1803         SDL_InvalidParamError("max_h");
  1804         return;
  1805     }
  1806 
  1807     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1808         window->max_w = max_w;
  1809         window->max_h = max_h;
  1810         if (_this->SetWindowMaximumSize) {
  1811             _this->SetWindowMaximumSize(_this, window);
  1812         }
  1813         /* Ensure that window is not larger than maximal size */
  1814         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1815     }
  1816 }
  1817 
  1818 void
  1819 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1820 {
  1821     CHECK_WINDOW_MAGIC(window,);
  1822     if (max_w) {
  1823         *max_w = window->max_w;
  1824     }
  1825     if (max_h) {
  1826         *max_h = window->max_h;
  1827     }
  1828 }
  1829 
  1830 void
  1831 SDL_ShowWindow(SDL_Window * window)
  1832 {
  1833     CHECK_WINDOW_MAGIC(window,);
  1834 
  1835     if (window->flags & SDL_WINDOW_SHOWN) {
  1836         return;
  1837     }
  1838 
  1839     if (_this->ShowWindow) {
  1840         _this->ShowWindow(_this, window);
  1841     }
  1842     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1843 }
  1844 
  1845 void
  1846 SDL_HideWindow(SDL_Window * window)
  1847 {
  1848     CHECK_WINDOW_MAGIC(window,);
  1849 
  1850     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1851         return;
  1852     }
  1853 
  1854 	window->is_hiding = SDL_TRUE;
  1855     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1856 
  1857     if (_this->HideWindow) {
  1858         _this->HideWindow(_this, window);
  1859     }
  1860 	window->is_hiding = SDL_FALSE;
  1861     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1862 }
  1863 
  1864 void
  1865 SDL_RaiseWindow(SDL_Window * window)
  1866 {
  1867     CHECK_WINDOW_MAGIC(window,);
  1868 
  1869     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1870         return;
  1871     }
  1872     if (_this->RaiseWindow) {
  1873         _this->RaiseWindow(_this, window);
  1874     }
  1875 }
  1876 
  1877 void
  1878 SDL_MaximizeWindow(SDL_Window * window)
  1879 {
  1880     CHECK_WINDOW_MAGIC(window,);
  1881 
  1882     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1883         return;
  1884     }
  1885 
  1886     /* !!! FIXME: should this check if the window is resizable? */
  1887 
  1888     if (_this->MaximizeWindow) {
  1889         _this->MaximizeWindow(_this, window);
  1890     }
  1891 }
  1892 
  1893 void
  1894 SDL_MinimizeWindow(SDL_Window * window)
  1895 {
  1896     CHECK_WINDOW_MAGIC(window,);
  1897 
  1898     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1899         return;
  1900     }
  1901 
  1902     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1903 
  1904     if (_this->MinimizeWindow) {
  1905         _this->MinimizeWindow(_this, window);
  1906     }
  1907 }
  1908 
  1909 void
  1910 SDL_RestoreWindow(SDL_Window * window)
  1911 {
  1912     CHECK_WINDOW_MAGIC(window,);
  1913 
  1914     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1915         return;
  1916     }
  1917 
  1918     if (_this->RestoreWindow) {
  1919         _this->RestoreWindow(_this, window);
  1920     }
  1921 }
  1922 
  1923 int
  1924 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1925 {
  1926     CHECK_WINDOW_MAGIC(window, -1);
  1927 
  1928     flags &= FULLSCREEN_MASK;
  1929 
  1930     if (flags == (window->flags & FULLSCREEN_MASK)) {
  1931         return 0;
  1932     }
  1933 
  1934     /* clear the previous flags and OR in the new ones */
  1935     window->flags &= ~FULLSCREEN_MASK;
  1936     window->flags |= flags;
  1937 
  1938     return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1939 }
  1940 
  1941 static SDL_Surface *
  1942 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1943 {
  1944     Uint32 format;
  1945     void *pixels;
  1946     int pitch;
  1947     int bpp;
  1948     Uint32 Rmask, Gmask, Bmask, Amask;
  1949 
  1950     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1951         return NULL;
  1952     }
  1953 
  1954     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1955         return NULL;
  1956     }
  1957 
  1958     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1959         return NULL;
  1960     }
  1961 
  1962     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1963 }
  1964 
  1965 SDL_Surface *
  1966 SDL_GetWindowSurface(SDL_Window * window)
  1967 {
  1968     CHECK_WINDOW_MAGIC(window, NULL);
  1969 
  1970     if (!window->surface_valid) {
  1971         if (window->surface) {
  1972             window->surface->flags &= ~SDL_DONTFREE;
  1973             SDL_FreeSurface(window->surface);
  1974         }
  1975         window->surface = SDL_CreateWindowFramebuffer(window);
  1976         if (window->surface) {
  1977             window->surface_valid = SDL_TRUE;
  1978             window->surface->flags |= SDL_DONTFREE;
  1979         }
  1980     }
  1981     return window->surface;
  1982 }
  1983 
  1984 int
  1985 SDL_UpdateWindowSurface(SDL_Window * window)
  1986 {
  1987     SDL_Rect full_rect;
  1988 
  1989     CHECK_WINDOW_MAGIC(window, -1);
  1990 
  1991     full_rect.x = 0;
  1992     full_rect.y = 0;
  1993     full_rect.w = window->w;
  1994     full_rect.h = window->h;
  1995     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1996 }
  1997 
  1998 int
  1999 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  2000                              int numrects)
  2001 {
  2002     CHECK_WINDOW_MAGIC(window, -1);
  2003 
  2004     if (!window->surface_valid) {
  2005         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  2006     }
  2007 
  2008     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  2009 }
  2010 
  2011 int
  2012 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  2013 {
  2014     Uint16 ramp[256];
  2015     int status;
  2016 
  2017     CHECK_WINDOW_MAGIC(window, -1);
  2018 
  2019     SDL_CalculateGammaRamp(brightness, ramp);
  2020     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  2021     if (status == 0) {
  2022         window->brightness = brightness;
  2023     }
  2024     return status;
  2025 }
  2026 
  2027 float
  2028 SDL_GetWindowBrightness(SDL_Window * window)
  2029 {
  2030     CHECK_WINDOW_MAGIC(window, 1.0f);
  2031 
  2032     return window->brightness;
  2033 }
  2034 
  2035 int
  2036 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  2037                                             const Uint16 * green,
  2038                                             const Uint16 * blue)
  2039 {
  2040     CHECK_WINDOW_MAGIC(window, -1);
  2041 
  2042     if (!_this->SetWindowGammaRamp) {
  2043         return SDL_Unsupported();
  2044     }
  2045 
  2046     if (!window->gamma) {
  2047         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  2048             return -1;
  2049         }
  2050     }
  2051 
  2052     if (red) {
  2053         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  2054     }
  2055     if (green) {
  2056         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  2057     }
  2058     if (blue) {
  2059         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  2060     }
  2061     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2062         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  2063     } else {
  2064         return 0;
  2065     }
  2066 }
  2067 
  2068 int
  2069 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  2070                                             Uint16 * green,
  2071                                             Uint16 * blue)
  2072 {
  2073     CHECK_WINDOW_MAGIC(window, -1);
  2074 
  2075     if (!window->gamma) {
  2076         int i;
  2077 
  2078         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  2079         if (!window->gamma) {
  2080             return SDL_OutOfMemory();
  2081         }
  2082         window->saved_gamma = window->gamma + 3*256;
  2083 
  2084         if (_this->GetWindowGammaRamp) {
  2085             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  2086                 return -1;
  2087             }
  2088         } else {
  2089             /* Create an identity gamma ramp */
  2090             for (i = 0; i < 256; ++i) {
  2091                 Uint16 value = (Uint16)((i << 8) | i);
  2092 
  2093                 window->gamma[0*256+i] = value;
  2094                 window->gamma[1*256+i] = value;
  2095                 window->gamma[2*256+i] = value;
  2096             }
  2097         }
  2098         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  2099     }
  2100 
  2101     if (red) {
  2102         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  2103     }
  2104     if (green) {
  2105         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  2106     }
  2107     if (blue) {
  2108         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  2109     }
  2110     return 0;
  2111 }
  2112 
  2113 void
  2114 SDL_UpdateWindowGrab(SDL_Window * window)
  2115 {
  2116     if (_this->SetWindowGrab) {
  2117         SDL_bool grabbed;
  2118         if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
  2119              (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  2120             grabbed = SDL_TRUE;
  2121         } else {
  2122             grabbed = SDL_FALSE;
  2123         }
  2124         _this->SetWindowGrab(_this, window, grabbed);
  2125     }
  2126 }
  2127 
  2128 void
  2129 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  2130 {
  2131     CHECK_WINDOW_MAGIC(window,);
  2132 
  2133     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  2134         return;
  2135     }
  2136     if (grabbed) {
  2137         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  2138     } else {
  2139         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2140     }
  2141     SDL_UpdateWindowGrab(window);
  2142 }
  2143 
  2144 SDL_bool
  2145 SDL_GetWindowGrab(SDL_Window * window)
  2146 {
  2147     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2148 
  2149     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  2150 }
  2151 
  2152 void
  2153 SDL_OnWindowShown(SDL_Window * window)
  2154 {
  2155     SDL_OnWindowRestored(window);
  2156 }
  2157 
  2158 void
  2159 SDL_OnWindowHidden(SDL_Window * window)
  2160 {
  2161     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2162 }
  2163 
  2164 void
  2165 SDL_OnWindowResized(SDL_Window * window)
  2166 {
  2167     window->surface_valid = SDL_FALSE;
  2168     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2169 }
  2170 
  2171 void
  2172 SDL_OnWindowMinimized(SDL_Window * window)
  2173 {
  2174     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2175 }
  2176 
  2177 void
  2178 SDL_OnWindowRestored(SDL_Window * window)
  2179 {
  2180     /*
  2181      * FIXME: Is this fine to just remove this, or should it be preserved just
  2182      * for the fullscreen case? In principle it seems like just hiding/showing
  2183      * windows shouldn't affect the stacking order; maybe the right fix is to
  2184      * re-decouple OnWindowShown and OnWindowRestored.
  2185      */
  2186     /*SDL_RaiseWindow(window);*/
  2187 
  2188     if (FULLSCREEN_VISIBLE(window)) {
  2189         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2190     }
  2191 }
  2192 
  2193 void
  2194 SDL_OnWindowEnter(SDL_Window * window)
  2195 {
  2196     if (_this->OnWindowEnter) {
  2197         _this->OnWindowEnter(_this, window);
  2198     }
  2199 }
  2200 
  2201 void
  2202 SDL_OnWindowLeave(SDL_Window * window)
  2203 {
  2204 }
  2205 
  2206 void
  2207 SDL_OnWindowFocusGained(SDL_Window * window)
  2208 {
  2209     SDL_Mouse *mouse = SDL_GetMouse();
  2210 
  2211     if (window->gamma && _this->SetWindowGammaRamp) {
  2212         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2213     }
  2214 
  2215     if (mouse && mouse->relative_mode) {
  2216         SDL_SetMouseFocus(window);
  2217         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2218     }
  2219 
  2220     SDL_UpdateWindowGrab(window);
  2221 }
  2222 
  2223 static SDL_bool
  2224 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2225 {
  2226     const char *hint;
  2227 
  2228     if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
  2229         return SDL_FALSE;
  2230     }
  2231 
  2232 #ifdef __MACOSX__
  2233     if (Cocoa_IsWindowInFullscreenSpace(window)) {
  2234         return SDL_FALSE;
  2235     }
  2236 #endif
  2237 
  2238     hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2239     if (hint) {
  2240         if (*hint == '0') {
  2241             return SDL_FALSE;
  2242         } else {
  2243             return SDL_TRUE;
  2244         }
  2245     }
  2246 
  2247     return SDL_TRUE;
  2248 }
  2249 
  2250 void
  2251 SDL_OnWindowFocusLost(SDL_Window * window)
  2252 {
  2253     if (window->gamma && _this->SetWindowGammaRamp) {
  2254         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2255     }
  2256 
  2257     SDL_UpdateWindowGrab(window);
  2258 
  2259     if (ShouldMinimizeOnFocusLoss(window)) {
  2260         SDL_MinimizeWindow(window);
  2261     }
  2262 }
  2263 
  2264 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
  2265    !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
  2266 SDL_Window *
  2267 SDL_GetFocusWindow(void)
  2268 {
  2269     SDL_Window *window;
  2270 
  2271     if (!_this) {
  2272         return NULL;
  2273     }
  2274     for (window = _this->windows; window; window = window->next) {
  2275         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2276             return window;
  2277         }
  2278     }
  2279     return NULL;
  2280 }
  2281 
  2282 void
  2283 SDL_DestroyWindow(SDL_Window * window)
  2284 {
  2285     SDL_VideoDisplay *display;
  2286 
  2287     CHECK_WINDOW_MAGIC(window,);
  2288 
  2289     window->is_destroying = SDL_TRUE;
  2290 
  2291     /* Restore video mode, etc. */
  2292     SDL_HideWindow(window);
  2293 
  2294     /* Make sure this window no longer has focus */
  2295     if (SDL_GetKeyboardFocus() == window) {
  2296         SDL_SetKeyboardFocus(NULL);
  2297     }
  2298     if (SDL_GetMouseFocus() == window) {
  2299         SDL_SetMouseFocus(NULL);
  2300     }
  2301 
  2302     /* make no context current if this is the current context window. */
  2303     if (window->flags & SDL_WINDOW_OPENGL) {
  2304         if (_this->current_glwin == window) {
  2305             SDL_GL_MakeCurrent(window, NULL);
  2306         }
  2307     }
  2308 
  2309     if (window->surface) {
  2310         window->surface->flags &= ~SDL_DONTFREE;
  2311         SDL_FreeSurface(window->surface);
  2312     }
  2313     if (_this->DestroyWindowFramebuffer) {
  2314         _this->DestroyWindowFramebuffer(_this, window);
  2315     }
  2316     if (_this->DestroyWindow) {
  2317         _this->DestroyWindow(_this, window);
  2318     }
  2319     if (window->flags & SDL_WINDOW_OPENGL) {
  2320         SDL_GL_UnloadLibrary();
  2321     }
  2322 
  2323     display = SDL_GetDisplayForWindow(window);
  2324     if (display->fullscreen_window == window) {
  2325         display->fullscreen_window = NULL;
  2326     }
  2327 
  2328     /* Now invalidate magic */
  2329     window->magic = NULL;
  2330 
  2331     /* Free memory associated with the window */
  2332     SDL_free(window->title);
  2333     SDL_FreeSurface(window->icon);
  2334     SDL_free(window->gamma);
  2335     while (window->data) {
  2336         SDL_WindowUserData *data = window->data;
  2337 
  2338         window->data = data->next;
  2339         SDL_free(data->name);
  2340         SDL_free(data);
  2341     }
  2342 
  2343     /* Unlink the window from the list */
  2344     if (window->next) {
  2345         window->next->prev = window->prev;
  2346     }
  2347     if (window->prev) {
  2348         window->prev->next = window->next;
  2349     } else {
  2350         _this->windows = window->next;
  2351     }
  2352 
  2353     SDL_free(window);
  2354 }
  2355 
  2356 SDL_bool
  2357 SDL_IsScreenSaverEnabled()
  2358 {
  2359     if (!_this) {
  2360         return SDL_TRUE;
  2361     }
  2362     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2363 }
  2364 
  2365 void
  2366 SDL_EnableScreenSaver()
  2367 {
  2368     if (!_this) {
  2369         return;
  2370     }
  2371     if (!_this->suspend_screensaver) {
  2372         return;
  2373     }
  2374     _this->suspend_screensaver = SDL_FALSE;
  2375     if (_this->SuspendScreenSaver) {
  2376         _this->SuspendScreenSaver(_this);
  2377     }
  2378 }
  2379 
  2380 void
  2381 SDL_DisableScreenSaver()
  2382 {
  2383     if (!_this) {
  2384         return;
  2385     }
  2386     if (_this->suspend_screensaver) {
  2387         return;
  2388     }
  2389     _this->suspend_screensaver = SDL_TRUE;
  2390     if (_this->SuspendScreenSaver) {
  2391         _this->SuspendScreenSaver(_this);
  2392     }
  2393 }
  2394 
  2395 void
  2396 SDL_VideoQuit(void)
  2397 {
  2398     int i, j;
  2399 
  2400     if (!_this) {
  2401         return;
  2402     }
  2403 
  2404     /* Halt event processing before doing anything else */
  2405     SDL_TouchQuit();
  2406     SDL_MouseQuit();
  2407     SDL_KeyboardQuit();
  2408     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2409 
  2410     SDL_EnableScreenSaver();
  2411 
  2412     /* Clean up the system video */
  2413     while (_this->windows) {
  2414         SDL_DestroyWindow(_this->windows);
  2415     }
  2416     _this->VideoQuit(_this);
  2417 
  2418     for (i = 0; i < _this->num_displays; ++i) {
  2419         SDL_VideoDisplay *display = &_this->displays[i];
  2420         for (j = display->num_display_modes; j--;) {
  2421             SDL_free(display->display_modes[j].driverdata);
  2422             display->display_modes[j].driverdata = NULL;
  2423         }
  2424         SDL_free(display->display_modes);
  2425         display->display_modes = NULL;
  2426         SDL_free(display->desktop_mode.driverdata);
  2427         display->desktop_mode.driverdata = NULL;
  2428         SDL_free(display->driverdata);
  2429         display->driverdata = NULL;
  2430     }
  2431     if (_this->displays) {
  2432         for (i = 0; i < _this->num_displays; ++i) {
  2433             SDL_free(_this->displays[i].name);
  2434         }
  2435         SDL_free(_this->displays);
  2436         _this->displays = NULL;
  2437         _this->num_displays = 0;
  2438     }
  2439     SDL_free(_this->clipboard_text);
  2440     _this->clipboard_text = NULL;
  2441     _this->free(_this);
  2442     _this = NULL;
  2443 }
  2444 
  2445 int
  2446 SDL_GL_LoadLibrary(const char *path)
  2447 {
  2448     int retval;
  2449 
  2450     if (!_this) {
  2451         return SDL_UninitializedVideo();
  2452     }
  2453     if (_this->gl_config.driver_loaded) {
  2454         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2455             return SDL_SetError("OpenGL library already loaded");
  2456         }
  2457         retval = 0;
  2458     } else {
  2459         if (!_this->GL_LoadLibrary) {
  2460             return SDL_SetError("No dynamic GL support in video driver");
  2461         }
  2462         retval = _this->GL_LoadLibrary(_this, path);
  2463     }
  2464     if (retval == 0) {
  2465         ++_this->gl_config.driver_loaded;
  2466     } else {
  2467         if (_this->GL_UnloadLibrary) {
  2468             _this->GL_UnloadLibrary(_this);
  2469         }
  2470     }
  2471     return (retval);
  2472 }
  2473 
  2474 void *
  2475 SDL_GL_GetProcAddress(const char *proc)
  2476 {
  2477     void *func;
  2478 
  2479     if (!_this) {
  2480         SDL_UninitializedVideo();
  2481         return NULL;
  2482     }
  2483     func = NULL;
  2484     if (_this->GL_GetProcAddress) {
  2485         if (_this->gl_config.driver_loaded) {
  2486             func = _this->GL_GetProcAddress(_this, proc);
  2487         } else {
  2488             SDL_SetError("No GL driver has been loaded");
  2489         }
  2490     } else {
  2491         SDL_SetError("No dynamic GL support in video driver");
  2492     }
  2493     return func;
  2494 }
  2495 
  2496 void
  2497 SDL_GL_UnloadLibrary(void)
  2498 {
  2499     if (!_this) {
  2500         SDL_UninitializedVideo();
  2501         return;
  2502     }
  2503     if (_this->gl_config.driver_loaded > 0) {
  2504         if (--_this->gl_config.driver_loaded > 0) {
  2505             return;
  2506         }
  2507         if (_this->GL_UnloadLibrary) {
  2508             _this->GL_UnloadLibrary(_this);
  2509         }
  2510     }
  2511 }
  2512 
  2513 static SDL_INLINE SDL_bool
  2514 isAtLeastGL3(const char *verstr)
  2515 {
  2516     return (verstr && (SDL_atoi(verstr) >= 3));
  2517 }
  2518 
  2519 SDL_bool
  2520 SDL_GL_ExtensionSupported(const char *extension)
  2521 {
  2522 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2523     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2524     const char *extensions;
  2525     const char *start;
  2526     const char *where, *terminator;
  2527 
  2528     /* Extension names should not have spaces. */
  2529     where = SDL_strchr(extension, ' ');
  2530     if (where || *extension == '\0') {
  2531         return SDL_FALSE;
  2532     }
  2533     /* See if there's an environment variable override */
  2534     start = SDL_getenv(extension);
  2535     if (start && *start == '0') {
  2536         return SDL_FALSE;
  2537     }
  2538 
  2539     /* Lookup the available extensions */
  2540 
  2541     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2542     if (!glGetStringFunc) {
  2543         return SDL_FALSE;
  2544     }
  2545 
  2546     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2547         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2548         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2549         GLint num_exts = 0;
  2550         GLint i;
  2551 
  2552         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2553         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2554         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2555             return SDL_FALSE;
  2556         }
  2557 
  2558         #ifndef GL_NUM_EXTENSIONS
  2559         #define GL_NUM_EXTENSIONS 0x821D
  2560         #endif
  2561         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2562         for (i = 0; i < num_exts; i++) {
  2563             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2564             if (SDL_strcmp(thisext, extension) == 0) {
  2565                 return SDL_TRUE;
  2566             }
  2567         }
  2568 
  2569         return SDL_FALSE;
  2570     }
  2571 
  2572     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2573 
  2574     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2575     if (!extensions) {
  2576         return SDL_FALSE;
  2577     }
  2578     /*
  2579      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2580      * extensions string. Don't be fooled by sub-strings, etc.
  2581      */
  2582 
  2583     start = extensions;
  2584 
  2585     for (;;) {
  2586         where = SDL_strstr(start, extension);
  2587         if (!where)
  2588             break;
  2589 
  2590         terminator = where + SDL_strlen(extension);
  2591         if (where == start || *(where - 1) == ' ')
  2592             if (*terminator == ' ' || *terminator == '\0')
  2593                 return SDL_TRUE;
  2594 
  2595         start = terminator;
  2596     }
  2597     return SDL_FALSE;
  2598 #else
  2599     return SDL_FALSE;
  2600 #endif
  2601 }
  2602 
  2603 void
  2604 SDL_GL_ResetAttributes()
  2605 {
  2606     if (!_this) {
  2607         return;
  2608     }
  2609 
  2610     _this->gl_config.red_size = 3;
  2611     _this->gl_config.green_size = 3;
  2612     _this->gl_config.blue_size = 2;
  2613     _this->gl_config.alpha_size = 0;
  2614     _this->gl_config.buffer_size = 0;
  2615     _this->gl_config.depth_size = 16;
  2616     _this->gl_config.stencil_size = 0;
  2617     _this->gl_config.double_buffer = 1;
  2618     _this->gl_config.accum_red_size = 0;
  2619     _this->gl_config.accum_green_size = 0;
  2620     _this->gl_config.accum_blue_size = 0;
  2621     _this->gl_config.accum_alpha_size = 0;
  2622     _this->gl_config.stereo = 0;
  2623     _this->gl_config.multisamplebuffers = 0;
  2624     _this->gl_config.multisamplesamples = 0;
  2625     _this->gl_config.retained_backing = 1;
  2626     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
  2627     _this->gl_config.profile_mask = 0;
  2628 #if SDL_VIDEO_OPENGL
  2629     _this->gl_config.major_version = 2;
  2630     _this->gl_config.minor_version = 1;
  2631 #elif SDL_VIDEO_OPENGL_ES2
  2632     _this->gl_config.major_version = 2;
  2633     _this->gl_config.minor_version = 0;
  2634     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2635 #elif SDL_VIDEO_OPENGL_ES
  2636     _this->gl_config.major_version = 1;
  2637     _this->gl_config.minor_version = 1;
  2638     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2639 #endif
  2640     _this->gl_config.flags = 0;
  2641     _this->gl_config.framebuffer_srgb_capable = 0;
  2642 
  2643     _this->gl_config.share_with_current_context = 0;
  2644 }
  2645 
  2646 int
  2647 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2648 {
  2649 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2650     int retval;
  2651 
  2652     if (!_this) {
  2653         return SDL_UninitializedVideo();
  2654     }
  2655     retval = 0;
  2656     switch (attr) {
  2657     case SDL_GL_RED_SIZE:
  2658         _this->gl_config.red_size = value;
  2659         break;
  2660     case SDL_GL_GREEN_SIZE:
  2661         _this->gl_config.green_size = value;
  2662         break;
  2663     case SDL_GL_BLUE_SIZE:
  2664         _this->gl_config.blue_size = value;
  2665         break;
  2666     case SDL_GL_ALPHA_SIZE:
  2667         _this->gl_config.alpha_size = value;
  2668         break;
  2669     case SDL_GL_DOUBLEBUFFER:
  2670         _this->gl_config.double_buffer = value;
  2671         break;
  2672     case SDL_GL_BUFFER_SIZE:
  2673         _this->gl_config.buffer_size = value;
  2674         break;
  2675     case SDL_GL_DEPTH_SIZE:
  2676         _this->gl_config.depth_size = value;
  2677         break;
  2678     case SDL_GL_STENCIL_SIZE:
  2679         _this->gl_config.stencil_size = value;
  2680         break;
  2681     case SDL_GL_ACCUM_RED_SIZE:
  2682         _this->gl_config.accum_red_size = value;
  2683         break;
  2684     case SDL_GL_ACCUM_GREEN_SIZE:
  2685         _this->gl_config.accum_green_size = value;
  2686         break;
  2687     case SDL_GL_ACCUM_BLUE_SIZE:
  2688         _this->gl_config.accum_blue_size = value;
  2689         break;
  2690     case SDL_GL_ACCUM_ALPHA_SIZE:
  2691         _this->gl_config.accum_alpha_size = value;
  2692         break;
  2693     case SDL_GL_STEREO:
  2694         _this->gl_config.stereo = value;
  2695         break;
  2696     case SDL_GL_MULTISAMPLEBUFFERS:
  2697         _this->gl_config.multisamplebuffers = value;
  2698         break;
  2699     case SDL_GL_MULTISAMPLESAMPLES:
  2700         _this->gl_config.multisamplesamples = value;
  2701         break;
  2702     case SDL_GL_ACCELERATED_VISUAL:
  2703         _this->gl_config.accelerated = value;
  2704         break;
  2705     case SDL_GL_RETAINED_BACKING:
  2706         _this->gl_config.retained_backing = value;
  2707         break;
  2708     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2709         _this->gl_config.major_version = value;
  2710         break;
  2711     case SDL_GL_CONTEXT_MINOR_VERSION:
  2712         _this->gl_config.minor_version = value;
  2713         break;
  2714     case SDL_GL_CONTEXT_EGL:
  2715         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2716         if (value != 0) {
  2717             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  2718         } else {
  2719             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  2720         };
  2721         break;
  2722     case SDL_GL_CONTEXT_FLAGS:
  2723         if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2724                       SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2725                       SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2726                       SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
  2727             retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2728             break;
  2729         }
  2730         _this->gl_config.flags = value;
  2731         break;
  2732     case SDL_GL_CONTEXT_PROFILE_MASK:
  2733         if (value != 0 &&
  2734             value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2735             value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2736             value != SDL_GL_CONTEXT_PROFILE_ES) {
  2737             retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2738             break;
  2739         }
  2740         _this->gl_config.profile_mask = value;
  2741         break;
  2742     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2743         _this->gl_config.share_with_current_context = value;
  2744         break;
  2745     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2746         _this->gl_config.framebuffer_srgb_capable = value;
  2747         break;
  2748     default:
  2749         retval = SDL_SetError("Unknown OpenGL attribute");
  2750         break;
  2751     }
  2752     return retval;
  2753 #else
  2754     return SDL_Unsupported();
  2755 #endif /* SDL_VIDEO_OPENGL */
  2756 }
  2757 
  2758 int
  2759 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2760 {
  2761 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2762     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2763     GLenum(APIENTRY * glGetErrorFunc) (void);
  2764     GLenum attrib = 0;
  2765     GLenum error = 0;
  2766 
  2767     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2768     if (!glGetIntegervFunc) {
  2769         return -1;
  2770     }
  2771 
  2772     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2773     if (!glGetErrorFunc) {
  2774         return -1;
  2775     }
  2776 
  2777     /* Clear value in any case */
  2778     *value = 0;
  2779 
  2780     switch (attr) {
  2781     case SDL_GL_RED_SIZE:
  2782         attrib = GL_RED_BITS;
  2783         break;
  2784     case SDL_GL_BLUE_SIZE:
  2785         attrib = GL_BLUE_BITS;
  2786         break;
  2787     case SDL_GL_GREEN_SIZE:
  2788         attrib = GL_GREEN_BITS;
  2789         break;
  2790     case SDL_GL_ALPHA_SIZE:
  2791         attrib = GL_ALPHA_BITS;
  2792         break;
  2793     case SDL_GL_DOUBLEBUFFER:
  2794 #if SDL_VIDEO_OPENGL
  2795         attrib = GL_DOUBLEBUFFER;
  2796         break;
  2797 #else
  2798         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2799         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2800         /* SDL driver must set proper value after initialization              */
  2801         *value = _this->gl_config.double_buffer;
  2802         return 0;
  2803 #endif
  2804     case SDL_GL_DEPTH_SIZE:
  2805         attrib = GL_DEPTH_BITS;
  2806         break;
  2807     case SDL_GL_STENCIL_SIZE:
  2808         attrib = GL_STENCIL_BITS;
  2809         break;
  2810 #if SDL_VIDEO_OPENGL
  2811     case SDL_GL_ACCUM_RED_SIZE:
  2812         attrib = GL_ACCUM_RED_BITS;
  2813         break;
  2814     case SDL_GL_ACCUM_GREEN_SIZE:
  2815         attrib = GL_ACCUM_GREEN_BITS;
  2816         break;
  2817     case SDL_GL_ACCUM_BLUE_SIZE:
  2818         attrib = GL_ACCUM_BLUE_BITS;
  2819         break;
  2820     case SDL_GL_ACCUM_ALPHA_SIZE:
  2821         attrib = GL_ACCUM_ALPHA_BITS;
  2822         break;
  2823     case SDL_GL_STEREO:
  2824         attrib = GL_STEREO;
  2825         break;
  2826 #else
  2827     case SDL_GL_ACCUM_RED_SIZE:
  2828     case SDL_GL_ACCUM_GREEN_SIZE:
  2829     case SDL_GL_ACCUM_BLUE_SIZE:
  2830     case SDL_GL_ACCUM_ALPHA_SIZE:
  2831     case SDL_GL_STEREO:
  2832         /* none of these are supported in OpenGL ES */
  2833         *value = 0;
  2834         return 0;
  2835 #endif
  2836     case SDL_GL_MULTISAMPLEBUFFERS:
  2837 #if SDL_VIDEO_OPENGL
  2838         attrib = GL_SAMPLE_BUFFERS_ARB;
  2839 #else
  2840         attrib = GL_SAMPLE_BUFFERS;
  2841 #endif
  2842         break;
  2843     case SDL_GL_MULTISAMPLESAMPLES:
  2844 #if SDL_VIDEO_OPENGL
  2845         attrib = GL_SAMPLES_ARB;
  2846 #else
  2847         attrib = GL_SAMPLES;
  2848 #endif
  2849         break;
  2850     case SDL_GL_BUFFER_SIZE:
  2851         {
  2852             GLint bits = 0;
  2853             GLint component;
  2854 
  2855             /*
  2856              * there doesn't seem to be a single flag in OpenGL
  2857              * for this!
  2858              */
  2859             glGetIntegervFunc(GL_RED_BITS, &component);
  2860             bits += component;
  2861             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2862             bits += component;
  2863             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2864             bits += component;
  2865             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2866             bits += component;
  2867 
  2868             *value = bits;
  2869             return 0;
  2870         }
  2871     case SDL_GL_ACCELERATED_VISUAL:
  2872         {
  2873             /* FIXME: How do we get this information? */
  2874             *value = (_this->gl_config.accelerated != 0);
  2875             return 0;
  2876         }
  2877     case SDL_GL_RETAINED_BACKING:
  2878         {
  2879             *value = _this->gl_config.retained_backing;
  2880             return 0;
  2881         }
  2882     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2883         {
  2884             *value = _this->gl_config.major_version;
  2885             return 0;
  2886         }
  2887     case SDL_GL_CONTEXT_MINOR_VERSION:
  2888         {
  2889             *value = _this->gl_config.minor_version;
  2890             return 0;
  2891         }
  2892     case SDL_GL_CONTEXT_EGL:
  2893         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2894         {
  2895             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  2896                 *value = 1;
  2897             }
  2898             else {
  2899                 *value = 0;
  2900             }
  2901             return 0;
  2902         }
  2903     case SDL_GL_CONTEXT_FLAGS:
  2904         {
  2905             *value = _this->gl_config.flags;
  2906             return 0;
  2907         }
  2908     case SDL_GL_CONTEXT_PROFILE_MASK:
  2909         {
  2910             *value = _this->gl_config.profile_mask;
  2911             return 0;
  2912         }
  2913     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2914         {
  2915             *value = _this->gl_config.share_with_current_context;
  2916             return 0;
  2917         }
  2918     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2919         {
  2920             *value = _this->gl_config.framebuffer_srgb_capable;
  2921             return 0;
  2922         }
  2923     default:
  2924         return SDL_SetError("Unknown OpenGL attribute");
  2925     }
  2926 
  2927     glGetIntegervFunc(attrib, (GLint *) value);
  2928     error = glGetErrorFunc();
  2929     if (error != GL_NO_ERROR) {
  2930         if (error == GL_INVALID_ENUM) {
  2931             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2932         } else if (error == GL_INVALID_VALUE) {
  2933             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2934         }
  2935         return SDL_SetError("OpenGL error: %08X", error);
  2936     }
  2937     return 0;
  2938 #else
  2939     return SDL_Unsupported();
  2940 #endif /* SDL_VIDEO_OPENGL */
  2941 }
  2942 
  2943 SDL_GLContext
  2944 SDL_GL_CreateContext(SDL_Window * window)
  2945 {
  2946     SDL_GLContext ctx = NULL;
  2947     CHECK_WINDOW_MAGIC(window, NULL);
  2948 
  2949     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2950         SDL_SetError("The specified window isn't an OpenGL window");
  2951         return NULL;
  2952     }
  2953 
  2954     ctx = _this->GL_CreateContext(_this, window);
  2955 
  2956     /* Creating a context is assumed to make it current in the SDL driver. */
  2957     if (ctx) {
  2958         _this->current_glwin = window;
  2959         _this->current_glctx = ctx;
  2960         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2961         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2962     }
  2963     return ctx;
  2964 }
  2965 
  2966 int
  2967 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2968 {
  2969     int retval;
  2970 
  2971     if (window == SDL_GL_GetCurrentWindow() &&
  2972         ctx == SDL_GL_GetCurrentContext()) {
  2973         /* We're already current. */
  2974         return 0;
  2975     }
  2976 
  2977     if (!ctx) {
  2978         window = NULL;
  2979     } else {
  2980         CHECK_WINDOW_MAGIC(window, -1);
  2981 
  2982         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2983             return SDL_SetError("The specified window isn't an OpenGL window");
  2984         }
  2985     }
  2986 
  2987     retval = _this->GL_MakeCurrent(_this, window, ctx);
  2988     if (retval == 0) {
  2989         _this->current_glwin = window;
  2990         _this->current_glctx = ctx;
  2991         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2992         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2993     }
  2994     return retval;
  2995 }
  2996 
  2997 SDL_Window *
  2998 SDL_GL_GetCurrentWindow(void)
  2999 {
  3000     if (!_this) {
  3001         SDL_UninitializedVideo();
  3002         return NULL;
  3003     }
  3004     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  3005 }
  3006 
  3007 SDL_GLContext
  3008 SDL_GL_GetCurrentContext(void)
  3009 {
  3010     if (!_this) {
  3011         SDL_UninitializedVideo();
  3012         return NULL;
  3013     }
  3014     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  3015 }
  3016 
  3017 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  3018 {
  3019     CHECK_WINDOW_MAGIC(window,);
  3020 
  3021     if (_this->GL_GetDrawableSize) {
  3022         _this->GL_GetDrawableSize(_this, window, w, h);
  3023     } else {
  3024         SDL_GetWindowSize(window, w, h);
  3025     }
  3026 }
  3027 
  3028 int
  3029 SDL_GL_SetSwapInterval(int interval)
  3030 {
  3031     if (!_this) {
  3032         return SDL_UninitializedVideo();
  3033     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3034         return SDL_SetError("No OpenGL context has been made current");
  3035     } else if (_this->GL_SetSwapInterval) {
  3036         return _this->GL_SetSwapInterval(_this, interval);
  3037     } else {
  3038         return SDL_SetError("Setting the swap interval is not supported");
  3039     }
  3040 }
  3041 
  3042 int
  3043 SDL_GL_GetSwapInterval(void)
  3044 {
  3045     if (!_this) {
  3046         return 0;
  3047     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3048         return 0;
  3049     } else if (_this->GL_GetSwapInterval) {
  3050         return _this->GL_GetSwapInterval(_this);
  3051     } else {
  3052         return 0;
  3053     }
  3054 }
  3055 
  3056 void
  3057 SDL_GL_SwapWindow(SDL_Window * window)
  3058 {
  3059     CHECK_WINDOW_MAGIC(window,);
  3060 
  3061     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3062         SDL_SetError("The specified window isn't an OpenGL window");
  3063         return;
  3064     }
  3065 
  3066     if (SDL_GL_GetCurrentWindow() != window) {
  3067         SDL_SetError("The specified window has not been made current");
  3068         return;
  3069     }
  3070 
  3071     _this->GL_SwapWindow(_this, window);
  3072 }
  3073 
  3074 void
  3075 SDL_GL_DeleteContext(SDL_GLContext context)
  3076 {
  3077     if (!_this || !context) {
  3078         return;
  3079     }
  3080 
  3081     if (SDL_GL_GetCurrentContext() == context) {
  3082         SDL_GL_MakeCurrent(NULL, NULL);
  3083     }
  3084 
  3085     _this->GL_DeleteContext(_this, context);
  3086 }
  3087 
  3088 #if 0                           /* FIXME */
  3089 /*
  3090  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  3091  * & 2 for alpha channel.
  3092  */
  3093 static void
  3094 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  3095 {
  3096     int x, y;
  3097     Uint32 colorkey;
  3098 #define SET_MASKBIT(icon, x, y, mask) \
  3099     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  3100 
  3101     colorkey = icon->format->colorkey;
  3102     switch (icon->format->BytesPerPixel) {
  3103     case 1:
  3104         {
  3105             Uint8 *pixels;
  3106             for (y = 0; y < icon->h; ++y) {
  3107                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  3108                 for (x = 0; x < icon->w; ++x) {
  3109                     if (*pixels++ == colorkey) {
  3110                         SET_MASKBIT(icon, x, y, mask);
  3111                     }
  3112                 }
  3113             }
  3114         }
  3115         break;
  3116 
  3117     case 2:
  3118         {
  3119             Uint16 *pixels;
  3120             for (y = 0; y < icon->h; ++y) {
  3121                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3122                 for (x = 0; x < icon->w; ++x) {
  3123                     if ((flags & 1) && *pixels == colorkey) {
  3124                         SET_MASKBIT(icon, x, y, mask);
  3125                     } else if ((flags & 2)
  3126                                && (*pixels & icon->format->Amask) == 0) {
  3127                         SET_MASKBIT(icon, x, y, mask);
  3128                     }
  3129                     pixels++;
  3130                 }
  3131             }
  3132         }
  3133         break;
  3134 
  3135     case 4:
  3136         {
  3137             Uint32 *pixels;
  3138             for (y = 0; y < icon->h; ++y) {
  3139                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3140                 for (x = 0; x < icon->w; ++x) {
  3141                     if ((flags & 1) && *pixels == colorkey) {
  3142                         SET_MASKBIT(icon, x, y, mask);
  3143                     } else if ((flags & 2)
  3144                                && (*pixels & icon->format->Amask) == 0) {
  3145                         SET_MASKBIT(icon, x, y, mask);
  3146                     }
  3147                     pixels++;
  3148                 }
  3149             }
  3150         }
  3151         break;
  3152     }
  3153 }
  3154 
  3155 /*
  3156  * Sets the window manager icon for the display window.
  3157  */
  3158 void
  3159 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3160 {
  3161     if (icon && _this->SetIcon) {
  3162         /* Generate a mask if necessary, and create the icon! */
  3163         if (mask == NULL) {
  3164             int mask_len = icon->h * (icon->w + 7) / 8;
  3165             int flags = 0;
  3166             mask = (Uint8 *) SDL_malloc(mask_len);
  3167             if (mask == NULL) {
  3168                 return;
  3169             }
  3170             SDL_memset(mask, ~0, mask_len);
  3171             if (icon->flags & SDL_SRCCOLORKEY)
  3172                 flags |= 1;
  3173             if (icon->flags & SDL_SRCALPHA)
  3174                 flags |= 2;
  3175             if (flags) {
  3176                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3177             }
  3178             _this->SetIcon(_this, icon, mask);
  3179             SDL_free(mask);
  3180         } else {
  3181             _this->SetIcon(_this, icon, mask);
  3182         }
  3183     }
  3184 }
  3185 #endif
  3186 
  3187 SDL_bool
  3188 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3189 {
  3190     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3191 
  3192     if (!info) {
  3193         SDL_InvalidParamError("info");
  3194         return SDL_FALSE;
  3195     }
  3196     info->subsystem = SDL_SYSWM_UNKNOWN;
  3197 
  3198     if (!_this->GetWindowWMInfo) {
  3199         SDL_Unsupported();
  3200         return SDL_FALSE;
  3201     }
  3202     return (_this->GetWindowWMInfo(_this, window, info));
  3203 }
  3204 
  3205 void
  3206 SDL_StartTextInput(void)
  3207 {
  3208     SDL_Window *window;
  3209 
  3210     /* First, enable text events */
  3211     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3212     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3213 
  3214     /* Then show the on-screen keyboard, if any */
  3215     window = SDL_GetFocusWindow();
  3216     if (window && _this && _this->ShowScreenKeyboard) {
  3217         _this->ShowScreenKeyboard(_this, window);
  3218     }
  3219 
  3220     /* Finally start the text input system */
  3221     if (_this && _this->StartTextInput) {
  3222         _this->StartTextInput(_this);
  3223     }
  3224 }
  3225 
  3226 SDL_bool
  3227 SDL_IsTextInputActive(void)
  3228 {
  3229     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3230 }
  3231 
  3232 void
  3233 SDL_StopTextInput(void)
  3234 {
  3235     SDL_Window *window;
  3236 
  3237     /* Stop the text input system */
  3238     if (_this && _this->StopTextInput) {
  3239         _this->StopTextInput(_this);
  3240     }
  3241 
  3242     /* Hide the on-screen keyboard, if any */
  3243     window = SDL_GetFocusWindow();
  3244     if (window && _this && _this->HideScreenKeyboard) {
  3245         _this->HideScreenKeyboard(_this, window);
  3246     }
  3247 
  3248     /* Finally disable text events */
  3249     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3250     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3251 }
  3252 
  3253 void
  3254 SDL_SetTextInputRect(SDL_Rect *rect)
  3255 {
  3256     if (_this && _this->SetTextInputRect) {
  3257         _this->SetTextInputRect(_this, rect);
  3258     }
  3259 }
  3260 
  3261 SDL_bool
  3262 SDL_HasScreenKeyboardSupport(void)
  3263 {
  3264     if (_this && _this->HasScreenKeyboardSupport) {
  3265         return _this->HasScreenKeyboardSupport(_this);
  3266     }
  3267     return SDL_FALSE;
  3268 }
  3269 
  3270 SDL_bool
  3271 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3272 {
  3273     if (window && _this && _this->IsScreenKeyboardShown) {
  3274         return _this->IsScreenKeyboardShown(_this, window);
  3275     }
  3276     return SDL_FALSE;
  3277 }
  3278 
  3279 #if SDL_VIDEO_DRIVER_ANDROID
  3280 #include "android/SDL_androidmessagebox.h"
  3281 #endif
  3282 #if SDL_VIDEO_DRIVER_WINDOWS
  3283 #include "windows/SDL_windowsmessagebox.h"
  3284 #endif
  3285 #if SDL_VIDEO_DRIVER_WINRT
  3286 #include "winrt/SDL_winrtmessagebox.h"
  3287 #endif
  3288 #if SDL_VIDEO_DRIVER_COCOA
  3289 #include "cocoa/SDL_cocoamessagebox.h"
  3290 #endif
  3291 #if SDL_VIDEO_DRIVER_UIKIT
  3292 #include "uikit/SDL_uikitmessagebox.h"
  3293 #endif
  3294 #if SDL_VIDEO_DRIVER_X11
  3295 #include "x11/SDL_x11messagebox.h"
  3296 #endif
  3297 
  3298 // This function will be unused if none of the above video drivers are present.
  3299 SDL_UNUSED static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3300 {
  3301     SDL_SysWMinfo info;
  3302     SDL_Window *window = messageboxdata->window;
  3303 
  3304     if (!window) {
  3305         return SDL_TRUE;
  3306     }
  3307 
  3308     SDL_VERSION(&info.version);
  3309     if (!SDL_GetWindowWMInfo(window, &info)) {
  3310         return SDL_TRUE;
  3311     } else {
  3312         return (info.subsystem == drivertype);
  3313     }
  3314 }
  3315 
  3316 int
  3317 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3318 {
  3319     int dummybutton;
  3320     int retval = -1;
  3321     SDL_bool relative_mode;
  3322     int show_cursor_prev;
  3323     SDL_bool mouse_captured;
  3324     SDL_Window *current_window;
  3325 
  3326     if (!messageboxdata) {
  3327         return SDL_InvalidParamError("messageboxdata");
  3328     }
  3329 
  3330     current_window = SDL_GetKeyboardFocus();
  3331     mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
  3332     relative_mode = SDL_GetRelativeMouseMode();
  3333     SDL_CaptureMouse(SDL_FALSE);
  3334     SDL_SetRelativeMouseMode(SDL_FALSE);
  3335     show_cursor_prev = SDL_ShowCursor(1);
  3336 
  3337     if (!buttonid) {
  3338         buttonid = &dummybutton;
  3339     }
  3340 
  3341     if (_this && _this->ShowMessageBox) {
  3342         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3343     }
  3344 
  3345     /* It's completely fine to call this function before video is initialized */
  3346 #if SDL_VIDEO_DRIVER_ANDROID
  3347     if (retval == -1 &&
  3348         Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3349         retval = 0;
  3350     }
  3351 #endif
  3352 #if SDL_VIDEO_DRIVER_WINDOWS
  3353     if (retval == -1 &&
  3354         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3355         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3356         retval = 0;
  3357     }
  3358 #endif
  3359 #if SDL_VIDEO_DRIVER_WINRT
  3360     if (retval == -1 &&
  3361         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
  3362         WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3363         retval = 0;
  3364     }
  3365 #endif
  3366 #if SDL_VIDEO_DRIVER_COCOA
  3367     if (retval == -1 &&
  3368         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3369         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3370         retval = 0;
  3371     }
  3372 #endif
  3373 #if SDL_VIDEO_DRIVER_UIKIT
  3374     if (retval == -1 &&
  3375         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3376         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3377         retval = 0;
  3378     }
  3379 #endif
  3380 #if SDL_VIDEO_DRIVER_X11
  3381     if (retval == -1 &&
  3382         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3383         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3384         retval = 0;
  3385     }
  3386 #endif
  3387     if (retval == -1) {
  3388         SDL_SetError("No message system available");
  3389     }
  3390 
  3391     if (current_window) {
  3392         SDL_RaiseWindow(current_window);
  3393         if (mouse_captured) {
  3394             SDL_CaptureMouse(SDL_TRUE);
  3395         }
  3396     }
  3397 
  3398     SDL_ShowCursor(show_cursor_prev);
  3399     SDL_SetRelativeMouseMode(relative_mode);
  3400 
  3401     return retval;
  3402 }
  3403 
  3404 int
  3405 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3406 {
  3407     SDL_MessageBoxData data;
  3408     SDL_MessageBoxButtonData button;
  3409 
  3410     SDL_zero(data);
  3411     data.flags = flags;
  3412     data.title = title;
  3413     data.message = message;
  3414     data.numbuttons = 1;
  3415     data.buttons = &button;
  3416     data.window = window;
  3417 
  3418     SDL_zero(button);
  3419     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3420     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3421     button.text = "OK";
  3422 
  3423     return SDL_ShowMessageBox(&data, NULL);
  3424 }
  3425 
  3426 SDL_bool
  3427 SDL_ShouldAllowTopmost(void)
  3428 {
  3429     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3430     if (hint) {
  3431         if (*hint == '0') {
  3432             return SDL_FALSE;
  3433         } else {
  3434             return SDL_TRUE;
  3435         }
  3436     }
  3437     return SDL_TRUE;
  3438 }
  3439 
  3440 int
  3441 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
  3442 {
  3443     CHECK_WINDOW_MAGIC(window, -1);
  3444 
  3445     if (!_this->SetWindowHitTest) {
  3446         return SDL_Unsupported();
  3447     } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
  3448         return -1;
  3449     }
  3450 
  3451     window->hit_test = callback;
  3452     window->hit_test_data = userdata;
  3453 
  3454     return 0;
  3455 }
  3456 
  3457 /* vi: set ts=4 sw=4 expandtab: */