src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 08 Apr 2015 02:00:14 -0400
changeset 9474 067b78126485
parent 9461 409b20ba3e70
child 9537 ff30c198864e
permissions -rw-r--r--
SDL_SetWindowTitle() should never set a NULL pointer for the title string.

Various backends reacted differently (or not at all) in the presence of a
NULL pointer. This simplifies things.

Fixes Bugzilla #2902.
     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 void
  1111 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1112 {
  1113     SDL_VideoDisplay *display;
  1114     SDL_Window *other;
  1115 
  1116     CHECK_WINDOW_MAGIC(window,);
  1117 
  1118     /* if we are in the process of hiding don't go back to fullscreen */
  1119     if ( window->is_hiding && fullscreen )
  1120         return;
  1121     
  1122 #ifdef __MACOSX__
  1123     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
  1124         window->last_fullscreen_flags = window->flags;
  1125         return;
  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;
  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                     SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1172                 } else {
  1173                     SDL_SetDisplayModeForDisplay(display, NULL);
  1174                 }
  1175 
  1176                 if (_this->SetWindowFullscreen) {
  1177                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1178                 }
  1179                 display->fullscreen_window = other;
  1180 
  1181                 /* Generate a mode change event here */
  1182                 if (resized) {
  1183                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1184                                         fullscreen_mode.w, fullscreen_mode.h);
  1185                 } else {
  1186                     SDL_OnWindowResized(other);
  1187                 }
  1188 
  1189                 SDL_RestoreMousePosition(other);
  1190 
  1191                 window->last_fullscreen_flags = window->flags;
  1192                 return;
  1193             }
  1194         }
  1195     }
  1196 
  1197     /* Nope, restore the desktop mode */
  1198     SDL_SetDisplayModeForDisplay(display, NULL);
  1199 
  1200     if (_this->SetWindowFullscreen) {
  1201         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1202     }
  1203     display->fullscreen_window = NULL;
  1204 
  1205     /* Generate a mode change event here */
  1206     SDL_OnWindowResized(window);
  1207 
  1208     /* Restore the cursor position */
  1209     SDL_RestoreMousePosition(window);
  1210 
  1211     window->last_fullscreen_flags = window->flags;
  1212 }
  1213 
  1214 #define CREATE_FLAGS \
  1215     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
  1216 
  1217 static void
  1218 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1219 {
  1220     window->windowed.x = window->x;
  1221     window->windowed.y = window->y;
  1222     window->windowed.w = window->w;
  1223     window->windowed.h = window->h;
  1224 
  1225     if (flags & SDL_WINDOW_MAXIMIZED) {
  1226         SDL_MaximizeWindow(window);
  1227     }
  1228     if (flags & SDL_WINDOW_MINIMIZED) {
  1229         SDL_MinimizeWindow(window);
  1230     }
  1231     if (flags & SDL_WINDOW_FULLSCREEN) {
  1232         SDL_SetWindowFullscreen(window, flags);
  1233     }
  1234     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1235         SDL_SetWindowGrab(window, SDL_TRUE);
  1236     }
  1237     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1238         SDL_ShowWindow(window);
  1239     }
  1240 }
  1241 
  1242 SDL_Window *
  1243 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1244 {
  1245     SDL_Window *window;
  1246     const char *hint;
  1247 
  1248     if (!_this) {
  1249         /* Initialize the video system if needed */
  1250         if (SDL_VideoInit(NULL) < 0) {
  1251             return NULL;
  1252         }
  1253     }
  1254 
  1255     /* Some platforms can't create zero-sized windows */
  1256     if (w < 1) {
  1257         w = 1;
  1258     }
  1259     if (h < 1) {
  1260         h = 1;
  1261     }
  1262 
  1263     /* Some platforms blow up if the windows are too large. Raise it later? */
  1264     if ((w > 16384) || (h > 16384)) {
  1265         SDL_SetError("Window is too large.");
  1266         return NULL;
  1267     }
  1268 
  1269     /* Some platforms have OpenGL enabled by default */
  1270 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
  1271     flags |= SDL_WINDOW_OPENGL;
  1272 #endif
  1273     if (flags & SDL_WINDOW_OPENGL) {
  1274         if (!_this->GL_CreateContext) {
  1275             SDL_SetError("No OpenGL support in video driver");
  1276             return NULL;
  1277         }
  1278         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1279             return NULL;
  1280         }
  1281     }
  1282 
  1283     /* Unless the user has specified the high-DPI disabling hint, respect the
  1284      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1285      */
  1286     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1287         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1288         if (hint && SDL_atoi(hint) > 0) {
  1289             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1290         }
  1291     }
  1292 
  1293     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1294     if (!window) {
  1295         SDL_OutOfMemory();
  1296         return NULL;
  1297     }
  1298     window->magic = &_this->window_magic;
  1299     window->id = _this->next_object_id++;
  1300     window->x = x;
  1301     window->y = y;
  1302     window->w = w;
  1303     window->h = h;
  1304     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1305         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1306         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1307         int displayIndex;
  1308         SDL_Rect bounds;
  1309 
  1310         displayIndex = SDL_GetIndexOfDisplay(display);
  1311         SDL_GetDisplayBounds(displayIndex, &bounds);
  1312         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1313             window->x = bounds.x + (bounds.w - w) / 2;
  1314         }
  1315         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1316             window->y = bounds.y + (bounds.h - h) / 2;
  1317         }
  1318     }
  1319     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1320     window->last_fullscreen_flags = window->flags;
  1321     window->brightness = 1.0f;
  1322     window->next = _this->windows;
  1323     window->is_destroying = SDL_FALSE;
  1324 
  1325     if (_this->windows) {
  1326         _this->windows->prev = window;
  1327     }
  1328     _this->windows = window;
  1329 
  1330     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1331         SDL_DestroyWindow(window);
  1332         return NULL;
  1333     }
  1334 
  1335     if (title) {
  1336         SDL_SetWindowTitle(window, title);
  1337     }
  1338     SDL_FinishWindowCreation(window, flags);
  1339 
  1340     /* If the window was created fullscreen, make sure the mode code matches */
  1341     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1342 
  1343     return window;
  1344 }
  1345 
  1346 SDL_Window *
  1347 SDL_CreateWindowFrom(const void *data)
  1348 {
  1349     SDL_Window *window;
  1350 
  1351     if (!_this) {
  1352         SDL_UninitializedVideo();
  1353         return NULL;
  1354     }
  1355     if (!_this->CreateWindowFrom) {
  1356         SDL_Unsupported();
  1357         return NULL;
  1358     }
  1359     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1360     if (!window) {
  1361         SDL_OutOfMemory();
  1362         return NULL;
  1363     }
  1364     window->magic = &_this->window_magic;
  1365     window->id = _this->next_object_id++;
  1366     window->flags = SDL_WINDOW_FOREIGN;
  1367     window->last_fullscreen_flags = window->flags;
  1368     window->is_destroying = SDL_FALSE;
  1369     window->brightness = 1.0f;
  1370     window->next = _this->windows;
  1371     if (_this->windows) {
  1372         _this->windows->prev = window;
  1373     }
  1374     _this->windows = window;
  1375 
  1376     if (_this->CreateWindowFrom(_this, window, data) < 0) {
  1377         SDL_DestroyWindow(window);
  1378         return NULL;
  1379     }
  1380     return window;
  1381 }
  1382 
  1383 int
  1384 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1385 {
  1386     char *title = window->title;
  1387     SDL_Surface *icon = window->icon;
  1388     SDL_bool loaded_opengl = SDL_FALSE;
  1389 
  1390     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1391         return SDL_SetError("No OpenGL support in video driver");
  1392     }
  1393 
  1394     if (window->flags & SDL_WINDOW_FOREIGN) {
  1395         /* Can't destroy and re-create foreign windows, hrm */
  1396         flags |= SDL_WINDOW_FOREIGN;
  1397     } else {
  1398         flags &= ~SDL_WINDOW_FOREIGN;
  1399     }
  1400 
  1401     /* Restore video mode, etc. */
  1402     SDL_HideWindow(window);
  1403 
  1404     /* Tear down the old native window */
  1405     if (window->surface) {
  1406         window->surface->flags &= ~SDL_DONTFREE;
  1407         SDL_FreeSurface(window->surface);
  1408     }
  1409     if (_this->DestroyWindowFramebuffer) {
  1410         _this->DestroyWindowFramebuffer(_this, window);
  1411     }
  1412     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1413         _this->DestroyWindow(_this, window);
  1414     }
  1415 
  1416     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1417         if (flags & SDL_WINDOW_OPENGL) {
  1418             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1419                 return -1;
  1420             }
  1421             loaded_opengl = SDL_TRUE;
  1422         } else {
  1423             SDL_GL_UnloadLibrary();
  1424         }
  1425     }
  1426 
  1427     window->title = NULL;
  1428     window->icon = NULL;
  1429     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1430     window->last_fullscreen_flags = window->flags;
  1431     window->is_destroying = SDL_FALSE;
  1432 
  1433     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1434         if (_this->CreateWindow(_this, window) < 0) {
  1435             if (loaded_opengl) {
  1436                 SDL_GL_UnloadLibrary();
  1437                 window->flags &= ~SDL_WINDOW_OPENGL;
  1438             }
  1439             return -1;
  1440         }
  1441     }
  1442     if (flags & SDL_WINDOW_FOREIGN) {
  1443         window->flags |= SDL_WINDOW_FOREIGN;
  1444     }
  1445 
  1446     if (title) {
  1447         SDL_SetWindowTitle(window, title);
  1448         SDL_free(title);
  1449     }
  1450     if (icon) {
  1451         SDL_SetWindowIcon(window, icon);
  1452         SDL_FreeSurface(icon);
  1453     }
  1454 
  1455     if (window->hit_test) {
  1456         _this->SetWindowHitTest(window, SDL_TRUE);
  1457     }
  1458 
  1459     SDL_FinishWindowCreation(window, flags);
  1460 
  1461     return 0;
  1462 }
  1463 
  1464 Uint32
  1465 SDL_GetWindowID(SDL_Window * window)
  1466 {
  1467     CHECK_WINDOW_MAGIC(window, 0);
  1468 
  1469     return window->id;
  1470 }
  1471 
  1472 SDL_Window *
  1473 SDL_GetWindowFromID(Uint32 id)
  1474 {
  1475     SDL_Window *window;
  1476 
  1477     if (!_this) {
  1478         return NULL;
  1479     }
  1480     for (window = _this->windows; window; window = window->next) {
  1481         if (window->id == id) {
  1482             return window;
  1483         }
  1484     }
  1485     return NULL;
  1486 }
  1487 
  1488 Uint32
  1489 SDL_GetWindowFlags(SDL_Window * window)
  1490 {
  1491     CHECK_WINDOW_MAGIC(window, 0);
  1492 
  1493     return window->flags;
  1494 }
  1495 
  1496 void
  1497 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1498 {
  1499     CHECK_WINDOW_MAGIC(window,);
  1500 
  1501     if (title == window->title) {
  1502         return;
  1503     }
  1504     SDL_free(window->title);
  1505 
  1506     window->title = SDL_strdup(title ? title : "");
  1507 
  1508     if (_this->SetWindowTitle) {
  1509         _this->SetWindowTitle(_this, window);
  1510     }
  1511 }
  1512 
  1513 const char *
  1514 SDL_GetWindowTitle(SDL_Window * window)
  1515 {
  1516     CHECK_WINDOW_MAGIC(window, "");
  1517 
  1518     return window->title ? window->title : "";
  1519 }
  1520 
  1521 void
  1522 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1523 {
  1524     CHECK_WINDOW_MAGIC(window,);
  1525 
  1526     if (!icon) {
  1527         return;
  1528     }
  1529 
  1530     SDL_FreeSurface(window->icon);
  1531 
  1532     /* Convert the icon into ARGB8888 */
  1533     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1534     if (!window->icon) {
  1535         return;
  1536     }
  1537 
  1538     if (_this->SetWindowIcon) {
  1539         _this->SetWindowIcon(_this, window, window->icon);
  1540     }
  1541 }
  1542 
  1543 void*
  1544 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1545 {
  1546     SDL_WindowUserData *prev, *data;
  1547 
  1548     CHECK_WINDOW_MAGIC(window, NULL);
  1549 
  1550     /* Input validation */
  1551     if (name == NULL || name[0] == '\0') {
  1552       SDL_InvalidParamError("name");
  1553       return NULL;
  1554     }
  1555 
  1556     /* See if the named data already exists */
  1557     prev = NULL;
  1558     for (data = window->data; data; prev = data, data = data->next) {
  1559         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1560             void *last_value = data->data;
  1561 
  1562             if (userdata) {
  1563                 /* Set the new value */
  1564                 data->data = userdata;
  1565             } else {
  1566                 /* Delete this value */
  1567                 if (prev) {
  1568                     prev->next = data->next;
  1569                 } else {
  1570                     window->data = data->next;
  1571                 }
  1572                 SDL_free(data->name);
  1573                 SDL_free(data);
  1574             }
  1575             return last_value;
  1576         }
  1577     }
  1578 
  1579     /* Add new data to the window */
  1580     if (userdata) {
  1581         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1582         data->name = SDL_strdup(name);
  1583         data->data = userdata;
  1584         data->next = window->data;
  1585         window->data = data;
  1586     }
  1587     return NULL;
  1588 }
  1589 
  1590 void *
  1591 SDL_GetWindowData(SDL_Window * window, const char *name)
  1592 {
  1593     SDL_WindowUserData *data;
  1594 
  1595     CHECK_WINDOW_MAGIC(window, NULL);
  1596 
  1597     /* Input validation */
  1598     if (name == NULL || name[0] == '\0') {
  1599       SDL_InvalidParamError("name");
  1600       return NULL;
  1601     }
  1602 
  1603     for (data = window->data; data; data = data->next) {
  1604         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1605             return data->data;
  1606         }
  1607     }
  1608     return NULL;
  1609 }
  1610 
  1611 void
  1612 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1613 {
  1614     CHECK_WINDOW_MAGIC(window,);
  1615 
  1616     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1617         int displayIndex = (x & 0xFFFF);
  1618         SDL_Rect bounds;
  1619         if (displayIndex > _this->num_displays) {
  1620             displayIndex = 0;
  1621         }
  1622 
  1623         SDL_zero(bounds);
  1624 
  1625         SDL_GetDisplayBounds(displayIndex, &bounds);
  1626         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1627             x = bounds.x + (bounds.w - window->w) / 2;
  1628         }
  1629         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1630             y = bounds.y + (bounds.h - window->h) / 2;
  1631         }
  1632     }
  1633 
  1634     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1635         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1636             window->windowed.x = x;
  1637         }
  1638         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1639             window->windowed.y = y;
  1640         }
  1641     } else {
  1642         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1643             window->x = x;
  1644         }
  1645         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1646             window->y = y;
  1647         }
  1648 
  1649         if (_this->SetWindowPosition) {
  1650             _this->SetWindowPosition(_this, window);
  1651         }
  1652         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1653     }
  1654 }
  1655 
  1656 void
  1657 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1658 {
  1659     CHECK_WINDOW_MAGIC(window,);
  1660 
  1661     /* Fullscreen windows are always at their display's origin */
  1662     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1663         if (x) {
  1664             *x = 0;
  1665         }
  1666         if (y) {
  1667             *y = 0;
  1668         }
  1669     } else {
  1670         if (x) {
  1671             *x = window->x;
  1672         }
  1673         if (y) {
  1674             *y = window->y;
  1675         }
  1676     }
  1677 }
  1678 
  1679 void
  1680 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1681 {
  1682     CHECK_WINDOW_MAGIC(window,);
  1683     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1684         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1685         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1686         if ((want != have) && (_this->SetWindowBordered)) {
  1687             if (want) {
  1688                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1689             } else {
  1690                 window->flags |= SDL_WINDOW_BORDERLESS;
  1691             }
  1692             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1693         }
  1694     }
  1695 }
  1696 
  1697 void
  1698 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1699 {
  1700     CHECK_WINDOW_MAGIC(window,);
  1701     if (w <= 0) {
  1702         SDL_InvalidParamError("w");
  1703         return;
  1704     }
  1705     if (h <= 0) {
  1706         SDL_InvalidParamError("h");
  1707         return;
  1708     }
  1709 
  1710     /* Make sure we don't exceed any window size limits */
  1711     if (window->min_w && w < window->min_w)
  1712     {
  1713         w = window->min_w;
  1714     }
  1715     if (window->max_w && w > window->max_w)
  1716     {
  1717         w = window->max_w;
  1718     }
  1719     if (window->min_h && h < window->min_h)
  1720     {
  1721         h = window->min_h;
  1722     }
  1723     if (window->max_h && h > window->max_h)
  1724     {
  1725         h = window->max_h;
  1726     }
  1727 
  1728     window->windowed.w = w;
  1729     window->windowed.h = h;
  1730 
  1731     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1732         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1733             window->last_fullscreen_flags = 0;
  1734             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1735         }
  1736     } else {
  1737         window->w = w;
  1738         window->h = h;
  1739         if (_this->SetWindowSize) {
  1740             _this->SetWindowSize(_this, window);
  1741         }
  1742         if (window->w == w && window->h == h) {
  1743             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1744             SDL_OnWindowResized(window);
  1745         }
  1746     }
  1747 }
  1748 
  1749 void
  1750 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1751 {
  1752     CHECK_WINDOW_MAGIC(window,);
  1753     if (w) {
  1754         *w = window->w;
  1755     }
  1756     if (h) {
  1757         *h = window->h;
  1758     }
  1759 }
  1760 
  1761 void
  1762 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1763 {
  1764     CHECK_WINDOW_MAGIC(window,);
  1765     if (min_w <= 0) {
  1766         SDL_InvalidParamError("min_w");
  1767         return;
  1768     }
  1769     if (min_h <= 0) {
  1770         SDL_InvalidParamError("min_h");
  1771         return;
  1772     }
  1773 
  1774     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1775         window->min_w = min_w;
  1776         window->min_h = min_h;
  1777         if (_this->SetWindowMinimumSize) {
  1778             _this->SetWindowMinimumSize(_this, window);
  1779         }
  1780         /* Ensure that window is not smaller than minimal size */
  1781         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1782     }
  1783 }
  1784 
  1785 void
  1786 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1787 {
  1788     CHECK_WINDOW_MAGIC(window,);
  1789     if (min_w) {
  1790         *min_w = window->min_w;
  1791     }
  1792     if (min_h) {
  1793         *min_h = window->min_h;
  1794     }
  1795 }
  1796 
  1797 void
  1798 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1799 {
  1800     CHECK_WINDOW_MAGIC(window,);
  1801     if (max_w <= 0) {
  1802         SDL_InvalidParamError("max_w");
  1803         return;
  1804     }
  1805     if (max_h <= 0) {
  1806         SDL_InvalidParamError("max_h");
  1807         return;
  1808     }
  1809 
  1810     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1811         window->max_w = max_w;
  1812         window->max_h = max_h;
  1813         if (_this->SetWindowMaximumSize) {
  1814             _this->SetWindowMaximumSize(_this, window);
  1815         }
  1816         /* Ensure that window is not larger than maximal size */
  1817         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1818     }
  1819 }
  1820 
  1821 void
  1822 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1823 {
  1824     CHECK_WINDOW_MAGIC(window,);
  1825     if (max_w) {
  1826         *max_w = window->max_w;
  1827     }
  1828     if (max_h) {
  1829         *max_h = window->max_h;
  1830     }
  1831 }
  1832 
  1833 void
  1834 SDL_ShowWindow(SDL_Window * window)
  1835 {
  1836     CHECK_WINDOW_MAGIC(window,);
  1837 
  1838     if (window->flags & SDL_WINDOW_SHOWN) {
  1839         return;
  1840     }
  1841 
  1842     if (_this->ShowWindow) {
  1843         _this->ShowWindow(_this, window);
  1844     }
  1845     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1846 }
  1847 
  1848 void
  1849 SDL_HideWindow(SDL_Window * window)
  1850 {
  1851     CHECK_WINDOW_MAGIC(window,);
  1852 
  1853     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1854         return;
  1855     }
  1856 
  1857 	window->is_hiding = SDL_TRUE;
  1858     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1859 
  1860     if (_this->HideWindow) {
  1861         _this->HideWindow(_this, window);
  1862     }
  1863 	window->is_hiding = SDL_FALSE;
  1864     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1865 }
  1866 
  1867 void
  1868 SDL_RaiseWindow(SDL_Window * window)
  1869 {
  1870     CHECK_WINDOW_MAGIC(window,);
  1871 
  1872     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1873         return;
  1874     }
  1875     if (_this->RaiseWindow) {
  1876         _this->RaiseWindow(_this, window);
  1877     }
  1878 }
  1879 
  1880 void
  1881 SDL_MaximizeWindow(SDL_Window * window)
  1882 {
  1883     CHECK_WINDOW_MAGIC(window,);
  1884 
  1885     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1886         return;
  1887     }
  1888 
  1889     /* !!! FIXME: should this check if the window is resizable? */
  1890 
  1891     if (_this->MaximizeWindow) {
  1892         _this->MaximizeWindow(_this, window);
  1893     }
  1894 }
  1895 
  1896 void
  1897 SDL_MinimizeWindow(SDL_Window * window)
  1898 {
  1899     CHECK_WINDOW_MAGIC(window,);
  1900 
  1901     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1902         return;
  1903     }
  1904 
  1905     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1906 
  1907     if (_this->MinimizeWindow) {
  1908         _this->MinimizeWindow(_this, window);
  1909     }
  1910 }
  1911 
  1912 void
  1913 SDL_RestoreWindow(SDL_Window * window)
  1914 {
  1915     CHECK_WINDOW_MAGIC(window,);
  1916 
  1917     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1918         return;
  1919     }
  1920 
  1921     if (_this->RestoreWindow) {
  1922         _this->RestoreWindow(_this, window);
  1923     }
  1924 }
  1925 
  1926 int
  1927 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1928 {
  1929     CHECK_WINDOW_MAGIC(window, -1);
  1930 
  1931     flags &= FULLSCREEN_MASK;
  1932 
  1933     if (flags == (window->flags & FULLSCREEN_MASK)) {
  1934         return 0;
  1935     }
  1936 
  1937     /* clear the previous flags and OR in the new ones */
  1938     window->flags &= ~FULLSCREEN_MASK;
  1939     window->flags |= flags;
  1940 
  1941     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1942 
  1943     return 0;
  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: */