src/video/SDL_video.c
author Pierre-Loup A. Griffais <pgriffais@valvesoftware.com>
Wed, 26 Mar 2014 12:54:51 -0700
changeset 8683 79527cb2cf8a
parent 8671 5e7004e87dec
child 8684 fd192408b830
permissions -rw-r--r--
Remove the RaiseWindow call from OnWindowRestored for now.

It seems like a net improvement in all the scenarios Sam and I could
think of, and looking at hg history it was added for fullscreen
window management specifically. Much of that code has changed since
then, but maybe it needs to stay there for that and simply be moved
to a fullscreen condition check.

It would solve this issue:

https://bugzilla.libsdl.org/show_bug.cgi?id=2439

As well as cases where on SteamOS, we hide/show specific Steam
overlay windows while expecting them to stay in the background, since
changing the window stacking order really angers the NVIDIA driver.

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