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