src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 09 Dec 2016 01:47:43 -0800
changeset 10690 23a825f341e6
parent 10650 b6ec7005ca15
child 10698 044ef09cda20
permissions -rw-r--r--
Fixed bug 3513 - SDL_GL_SwapWindow does not return error status

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