src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 15 Jun 2015 23:44:08 -0700
changeset 9745 885b6b5c8426
parent 9642 cd237569d0f6
child 9776 952ff8a5076f
permissions -rw-r--r--
Fixed bug 3015 - grab mouse inconsistent state

Martin Gerhardy

Not sure - but I think there might be a logic flaw in SDL_SetWindowGrab.

The problem here is that this modifies the window flags and e.g. sets
SDL_WINDOW_INPUT_GRABBED - but the _this->grabbed_window pointer is not
yet set.

Then in SDL_UpdateWindowGrab the _this->grabbed_window pointer is only
set if the function pointer _this->SetWindowGrab is not NULL. But if
this is NULL, the _this->grabbed_window pointer is never set, but every
future call to any of the grab functions include an assert for:
SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags &
SDL_WINDOW_INPUT_GRABBED) != 0));

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