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