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