src/video/SDL_video.c
author Ryan C. Gordon
Tue, 06 Sep 2016 13:13:03 -0400
changeset 10312 943b722a8e61
parent 10166 2393160743ca
child 10385 ad12658bc7ae
permissions -rw-r--r--
emscripten: special case to make SDL_ShowSimpleMessageBox() work.

Browsers don't have the functionality to fully support the generic
SDL_ShowMessageBox(), but this handles the likely most-common case.

Without this, you'd return immediately with a proper error result and no UI,
but probably no one checks that for SDL_ShowSimpleMessageBox. And if they
did: what would they do to handle this anyhow?

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