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