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