src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 22 Jun 2015 23:36:06 -0700
changeset 9776 952ff8a5076f
parent 9745 885b6b5c8426
child 9813 0652406e46c6
permissions -rw-r--r--
Fixed bug 3030 - SDL_RecreateWindow fails to restore title, icon, etc.

Adam M.

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