src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 07 Oct 2016 18:09:09 -0700
changeset 10491 c64e191b5518
parent 10385 ad12658bc7ae
child 10499 363c1c7e7a41
permissions -rw-r--r--
Fixed bug 3061 - Selecting the dummy video driver on Mac OS X results in an error

Darren Kulp

The dummy video driver is not available on Mac OS X if SDL_VIDEO_OPENGL is set at library compilation time.

In src/video/SDL_video.c, there is a compile-time check in SDL_CreateWindow() for (SDL_VIDEO_OPENGL && __MACOSX__). When it succeeds, SDL_WINDOW_OPENGL is always requested. Since the dummy video driver does not supply an OpenGL implementation, the error "No OpenGL support in video driver" is supplied to the user, and SDL_CreateWindow() is exited early.
     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     if (SDL_strcmp(_this->name, "dummy") != 0) {
  1370         flags |= SDL_WINDOW_OPENGL;
  1371     }
  1372 #endif
  1373     if (flags & SDL_WINDOW_OPENGL) {
  1374         if (!_this->GL_CreateContext) {
  1375             SDL_SetError("No OpenGL support in video driver");
  1376             return NULL;
  1377         }
  1378         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1379             return NULL;
  1380         }
  1381     }
  1382 
  1383     /* Unless the user has specified the high-DPI disabling hint, respect the
  1384      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1385      */
  1386     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1387         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1388         if (hint && SDL_atoi(hint) > 0) {
  1389             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1390         }
  1391     }
  1392 
  1393     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1394     if (!window) {
  1395         SDL_OutOfMemory();
  1396         return NULL;
  1397     }
  1398     window->magic = &_this->window_magic;
  1399     window->id = _this->next_object_id++;
  1400     window->x = x;
  1401     window->y = y;
  1402     window->w = w;
  1403     window->h = h;
  1404     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1405         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1406         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1407         int displayIndex;
  1408         SDL_Rect bounds;
  1409 
  1410         displayIndex = SDL_GetIndexOfDisplay(display);
  1411         SDL_GetDisplayBounds(displayIndex, &bounds);
  1412         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1413             window->x = bounds.x + (bounds.w - w) / 2;
  1414         }
  1415         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1416             window->y = bounds.y + (bounds.h - h) / 2;
  1417         }
  1418     }
  1419     window->windowed.x = window->x;
  1420     window->windowed.y = window->y;
  1421     window->windowed.w = window->w;
  1422     window->windowed.h = window->h;
  1423 
  1424     if (flags & SDL_WINDOW_FULLSCREEN) {
  1425         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1426         int displayIndex;
  1427         SDL_Rect bounds;
  1428 
  1429         displayIndex = SDL_GetIndexOfDisplay(display);
  1430         SDL_GetDisplayBounds(displayIndex, &bounds);
  1431 
  1432         window->x = bounds.x;
  1433         window->y = bounds.y;
  1434         window->w = bounds.w;
  1435         window->h = bounds.h;
  1436     }
  1437 
  1438     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1439     window->last_fullscreen_flags = window->flags;
  1440     window->opacity = 1.0f;
  1441     window->brightness = 1.0f;
  1442     window->next = _this->windows;
  1443     window->is_destroying = SDL_FALSE;
  1444 
  1445     if (_this->windows) {
  1446         _this->windows->prev = window;
  1447     }
  1448     _this->windows = window;
  1449 
  1450     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1451         SDL_DestroyWindow(window);
  1452         return NULL;
  1453     }
  1454 
  1455 #if __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
  1456     /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
  1457        or not.  The user can choose this, via OS-provided UI, but this can't
  1458        be set programmatically.
  1459 
  1460        Just look at what SDL's WinRT video backend code detected with regards
  1461        to fullscreen (being active, or not), and figure out a return/error code
  1462        from that.
  1463     */
  1464     flags = window->flags;
  1465 #endif
  1466 
  1467     if (title) {
  1468         SDL_SetWindowTitle(window, title);
  1469     }
  1470     SDL_FinishWindowCreation(window, flags);
  1471 
  1472     /* If the window was created fullscreen, make sure the mode code matches */
  1473     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1474 
  1475     return window;
  1476 }
  1477 
  1478 SDL_Window *
  1479 SDL_CreateWindowFrom(const void *data)
  1480 {
  1481     SDL_Window *window;
  1482 
  1483     if (!_this) {
  1484         SDL_UninitializedVideo();
  1485         return NULL;
  1486     }
  1487     if (!_this->CreateWindowFrom) {
  1488         SDL_Unsupported();
  1489         return NULL;
  1490     }
  1491     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1492     if (!window) {
  1493         SDL_OutOfMemory();
  1494         return NULL;
  1495     }
  1496     window->magic = &_this->window_magic;
  1497     window->id = _this->next_object_id++;
  1498     window->flags = SDL_WINDOW_FOREIGN;
  1499     window->last_fullscreen_flags = window->flags;
  1500     window->is_destroying = SDL_FALSE;
  1501     window->opacity = 1.0f;
  1502     window->brightness = 1.0f;
  1503     window->next = _this->windows;
  1504     if (_this->windows) {
  1505         _this->windows->prev = window;
  1506     }
  1507     _this->windows = window;
  1508 
  1509     if (_this->CreateWindowFrom(_this, window, data) < 0) {
  1510         SDL_DestroyWindow(window);
  1511         return NULL;
  1512     }
  1513     return window;
  1514 }
  1515 
  1516 int
  1517 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1518 {
  1519     SDL_bool loaded_opengl = SDL_FALSE;
  1520 
  1521     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1522         return SDL_SetError("No OpenGL support in video driver");
  1523     }
  1524 
  1525     if (window->flags & SDL_WINDOW_FOREIGN) {
  1526         /* Can't destroy and re-create foreign windows, hrm */
  1527         flags |= SDL_WINDOW_FOREIGN;
  1528     } else {
  1529         flags &= ~SDL_WINDOW_FOREIGN;
  1530     }
  1531 
  1532     /* Restore video mode, etc. */
  1533     SDL_HideWindow(window);
  1534 
  1535     /* Tear down the old native window */
  1536     if (window->surface) {
  1537         window->surface->flags &= ~SDL_DONTFREE;
  1538         SDL_FreeSurface(window->surface);
  1539         window->surface = NULL;
  1540     }
  1541     if (_this->DestroyWindowFramebuffer) {
  1542         _this->DestroyWindowFramebuffer(_this, window);
  1543     }
  1544     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1545         _this->DestroyWindow(_this, window);
  1546     }
  1547 
  1548     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1549         if (flags & SDL_WINDOW_OPENGL) {
  1550             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1551                 return -1;
  1552             }
  1553             loaded_opengl = SDL_TRUE;
  1554         } else {
  1555             SDL_GL_UnloadLibrary();
  1556         }
  1557     }
  1558 
  1559     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1560     window->last_fullscreen_flags = window->flags;
  1561     window->is_destroying = SDL_FALSE;
  1562 
  1563     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1564         if (_this->CreateWindow(_this, window) < 0) {
  1565             if (loaded_opengl) {
  1566                 SDL_GL_UnloadLibrary();
  1567                 window->flags &= ~SDL_WINDOW_OPENGL;
  1568             }
  1569             return -1;
  1570         }
  1571     }
  1572 
  1573     if (flags & SDL_WINDOW_FOREIGN) {
  1574         window->flags |= SDL_WINDOW_FOREIGN;
  1575     }
  1576 
  1577     if (_this->SetWindowTitle && window->title) {
  1578         _this->SetWindowTitle(_this, window);
  1579     }
  1580 
  1581     if (_this->SetWindowIcon && window->icon) {
  1582         _this->SetWindowIcon(_this, window, window->icon);
  1583     }
  1584 
  1585     if (window->hit_test) {
  1586         _this->SetWindowHitTest(window, SDL_TRUE);
  1587     }
  1588 
  1589     SDL_FinishWindowCreation(window, flags);
  1590 
  1591     return 0;
  1592 }
  1593 
  1594 Uint32
  1595 SDL_GetWindowID(SDL_Window * window)
  1596 {
  1597     CHECK_WINDOW_MAGIC(window, 0);
  1598 
  1599     return window->id;
  1600 }
  1601 
  1602 SDL_Window *
  1603 SDL_GetWindowFromID(Uint32 id)
  1604 {
  1605     SDL_Window *window;
  1606 
  1607     if (!_this) {
  1608         return NULL;
  1609     }
  1610     for (window = _this->windows; window; window = window->next) {
  1611         if (window->id == id) {
  1612             return window;
  1613         }
  1614     }
  1615     return NULL;
  1616 }
  1617 
  1618 Uint32
  1619 SDL_GetWindowFlags(SDL_Window * window)
  1620 {
  1621     CHECK_WINDOW_MAGIC(window, 0);
  1622 
  1623     return window->flags;
  1624 }
  1625 
  1626 void
  1627 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1628 {
  1629     CHECK_WINDOW_MAGIC(window,);
  1630 
  1631     if (title == window->title) {
  1632         return;
  1633     }
  1634     SDL_free(window->title);
  1635 
  1636     window->title = SDL_strdup(title ? title : "");
  1637 
  1638     if (_this->SetWindowTitle) {
  1639         _this->SetWindowTitle(_this, window);
  1640     }
  1641 }
  1642 
  1643 const char *
  1644 SDL_GetWindowTitle(SDL_Window * window)
  1645 {
  1646     CHECK_WINDOW_MAGIC(window, "");
  1647 
  1648     return window->title ? window->title : "";
  1649 }
  1650 
  1651 void
  1652 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1653 {
  1654     CHECK_WINDOW_MAGIC(window,);
  1655 
  1656     if (!icon) {
  1657         return;
  1658     }
  1659 
  1660     SDL_FreeSurface(window->icon);
  1661 
  1662     /* Convert the icon into ARGB8888 */
  1663     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1664     if (!window->icon) {
  1665         return;
  1666     }
  1667 
  1668     if (_this->SetWindowIcon) {
  1669         _this->SetWindowIcon(_this, window, window->icon);
  1670     }
  1671 }
  1672 
  1673 void*
  1674 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1675 {
  1676     SDL_WindowUserData *prev, *data;
  1677 
  1678     CHECK_WINDOW_MAGIC(window, NULL);
  1679 
  1680     /* Input validation */
  1681     if (name == NULL || name[0] == '\0') {
  1682       SDL_InvalidParamError("name");
  1683       return NULL;
  1684     }
  1685 
  1686     /* See if the named data already exists */
  1687     prev = NULL;
  1688     for (data = window->data; data; prev = data, data = data->next) {
  1689         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1690             void *last_value = data->data;
  1691 
  1692             if (userdata) {
  1693                 /* Set the new value */
  1694                 data->data = userdata;
  1695             } else {
  1696                 /* Delete this value */
  1697                 if (prev) {
  1698                     prev->next = data->next;
  1699                 } else {
  1700                     window->data = data->next;
  1701                 }
  1702                 SDL_free(data->name);
  1703                 SDL_free(data);
  1704             }
  1705             return last_value;
  1706         }
  1707     }
  1708 
  1709     /* Add new data to the window */
  1710     if (userdata) {
  1711         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1712         data->name = SDL_strdup(name);
  1713         data->data = userdata;
  1714         data->next = window->data;
  1715         window->data = data;
  1716     }
  1717     return NULL;
  1718 }
  1719 
  1720 void *
  1721 SDL_GetWindowData(SDL_Window * window, const char *name)
  1722 {
  1723     SDL_WindowUserData *data;
  1724 
  1725     CHECK_WINDOW_MAGIC(window, NULL);
  1726 
  1727     /* Input validation */
  1728     if (name == NULL || name[0] == '\0') {
  1729       SDL_InvalidParamError("name");
  1730       return NULL;
  1731     }
  1732 
  1733     for (data = window->data; data; data = data->next) {
  1734         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1735             return data->data;
  1736         }
  1737     }
  1738     return NULL;
  1739 }
  1740 
  1741 void
  1742 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1743 {
  1744     CHECK_WINDOW_MAGIC(window,);
  1745 
  1746     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1747         int displayIndex = (x & 0xFFFF);
  1748         SDL_Rect bounds;
  1749         if (displayIndex > _this->num_displays) {
  1750             displayIndex = 0;
  1751         }
  1752 
  1753         SDL_zero(bounds);
  1754 
  1755         SDL_GetDisplayBounds(displayIndex, &bounds);
  1756         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1757             x = bounds.x + (bounds.w - window->w) / 2;
  1758         }
  1759         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1760             y = bounds.y + (bounds.h - window->h) / 2;
  1761         }
  1762     }
  1763 
  1764     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1765         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1766             window->windowed.x = x;
  1767         }
  1768         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1769             window->windowed.y = y;
  1770         }
  1771     } else {
  1772         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1773             window->x = x;
  1774         }
  1775         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1776             window->y = y;
  1777         }
  1778 
  1779         if (_this->SetWindowPosition) {
  1780             _this->SetWindowPosition(_this, window);
  1781         }
  1782         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1783     }
  1784 }
  1785 
  1786 void
  1787 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1788 {
  1789     CHECK_WINDOW_MAGIC(window,);
  1790 
  1791     /* Fullscreen windows are always at their display's origin */
  1792     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1793         int displayIndex;
  1794         
  1795         if (x) {
  1796             *x = 0;
  1797         }
  1798         if (y) {
  1799             *y = 0;
  1800         }
  1801 
  1802         /* Find the window's monitor and update to the
  1803            monitor offset. */
  1804         displayIndex = SDL_GetWindowDisplayIndex(window);
  1805         if (displayIndex >= 0) {
  1806             SDL_Rect bounds;
  1807 
  1808             SDL_zero(bounds);
  1809 
  1810             SDL_GetDisplayBounds(displayIndex, &bounds);
  1811             if (x) {
  1812                 *x = bounds.x;
  1813             }
  1814             if (y) {
  1815                 *y = bounds.y;
  1816             }
  1817         }
  1818     } else {
  1819         if (x) {
  1820             *x = window->x;
  1821         }
  1822         if (y) {
  1823             *y = window->y;
  1824         }
  1825     }
  1826 }
  1827 
  1828 void
  1829 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1830 {
  1831     CHECK_WINDOW_MAGIC(window,);
  1832     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1833         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1834         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1835         if ((want != have) && (_this->SetWindowBordered)) {
  1836             if (want) {
  1837                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1838             } else {
  1839                 window->flags |= SDL_WINDOW_BORDERLESS;
  1840             }
  1841             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1842         }
  1843     }
  1844 }
  1845 
  1846 void
  1847 SDL_SetWindowResizable(SDL_Window * window, SDL_bool resizable)
  1848 {
  1849     CHECK_WINDOW_MAGIC(window,);
  1850     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1851         const int want = (resizable != SDL_FALSE);  /* normalize the flag. */
  1852         const int have = ((window->flags & SDL_WINDOW_RESIZABLE) != 0);
  1853         if ((want != have) && (_this->SetWindowResizable)) {
  1854             if (want) {
  1855                 window->flags |= SDL_WINDOW_RESIZABLE;
  1856             } else {
  1857                 window->flags &= ~SDL_WINDOW_RESIZABLE;
  1858             }
  1859             _this->SetWindowResizable(_this, window, (SDL_bool) want);
  1860         }
  1861     }
  1862 }
  1863 
  1864 void
  1865 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1866 {
  1867     CHECK_WINDOW_MAGIC(window,);
  1868     if (w <= 0) {
  1869         SDL_InvalidParamError("w");
  1870         return;
  1871     }
  1872     if (h <= 0) {
  1873         SDL_InvalidParamError("h");
  1874         return;
  1875     }
  1876 
  1877     /* Make sure we don't exceed any window size limits */
  1878     if (window->min_w && w < window->min_w)
  1879     {
  1880         w = window->min_w;
  1881     }
  1882     if (window->max_w && w > window->max_w)
  1883     {
  1884         w = window->max_w;
  1885     }
  1886     if (window->min_h && h < window->min_h)
  1887     {
  1888         h = window->min_h;
  1889     }
  1890     if (window->max_h && h > window->max_h)
  1891     {
  1892         h = window->max_h;
  1893     }
  1894 
  1895     window->windowed.w = w;
  1896     window->windowed.h = h;
  1897 
  1898     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1899         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1900             window->last_fullscreen_flags = 0;
  1901             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1902         }
  1903     } else {
  1904         window->w = w;
  1905         window->h = h;
  1906         if (_this->SetWindowSize) {
  1907             _this->SetWindowSize(_this, window);
  1908         }
  1909         if (window->w == w && window->h == h) {
  1910             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1911             SDL_OnWindowResized(window);
  1912         }
  1913     }
  1914 }
  1915 
  1916 void
  1917 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1918 {
  1919     CHECK_WINDOW_MAGIC(window,);
  1920     if (w) {
  1921         *w = window->w;
  1922     }
  1923     if (h) {
  1924         *h = window->h;
  1925     }
  1926 }
  1927 
  1928 void
  1929 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1930 {
  1931     CHECK_WINDOW_MAGIC(window,);
  1932     if (min_w <= 0) {
  1933         SDL_InvalidParamError("min_w");
  1934         return;
  1935     }
  1936     if (min_h <= 0) {
  1937         SDL_InvalidParamError("min_h");
  1938         return;
  1939     }
  1940 
  1941     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1942         window->min_w = min_w;
  1943         window->min_h = min_h;
  1944         if (_this->SetWindowMinimumSize) {
  1945             _this->SetWindowMinimumSize(_this, window);
  1946         }
  1947         /* Ensure that window is not smaller than minimal size */
  1948         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1949     }
  1950 }
  1951 
  1952 int
  1953 SDL_GetWindowBordersSize(SDL_Window * window, int *top, int *left, int *bottom, int *right)
  1954 {
  1955     int dummy = 0;
  1956 
  1957     if (!top) { top = &dummy; }
  1958     if (!left) { left = &dummy; }
  1959     if (!right) { right = &dummy; }
  1960     if (!bottom) { bottom = &dummy; }
  1961 
  1962     /* Always initialize, so applications don't have to care */
  1963     *top = *left = *bottom = *right = 0;
  1964 
  1965     CHECK_WINDOW_MAGIC(window, -1);
  1966 
  1967     if (!_this->GetWindowBordersSize) {
  1968         return SDL_Unsupported();
  1969     }
  1970 
  1971     return _this->GetWindowBordersSize(_this, window, top, left, bottom, right);
  1972 }
  1973 
  1974 void
  1975 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1976 {
  1977     CHECK_WINDOW_MAGIC(window,);
  1978     if (min_w) {
  1979         *min_w = window->min_w;
  1980     }
  1981     if (min_h) {
  1982         *min_h = window->min_h;
  1983     }
  1984 }
  1985 
  1986 void
  1987 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1988 {
  1989     CHECK_WINDOW_MAGIC(window,);
  1990     if (max_w <= 0) {
  1991         SDL_InvalidParamError("max_w");
  1992         return;
  1993     }
  1994     if (max_h <= 0) {
  1995         SDL_InvalidParamError("max_h");
  1996         return;
  1997     }
  1998 
  1999     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  2000         window->max_w = max_w;
  2001         window->max_h = max_h;
  2002         if (_this->SetWindowMaximumSize) {
  2003             _this->SetWindowMaximumSize(_this, window);
  2004         }
  2005         /* Ensure that window is not larger than maximal size */
  2006         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  2007     }
  2008 }
  2009 
  2010 void
  2011 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  2012 {
  2013     CHECK_WINDOW_MAGIC(window,);
  2014     if (max_w) {
  2015         *max_w = window->max_w;
  2016     }
  2017     if (max_h) {
  2018         *max_h = window->max_h;
  2019     }
  2020 }
  2021 
  2022 void
  2023 SDL_ShowWindow(SDL_Window * window)
  2024 {
  2025     CHECK_WINDOW_MAGIC(window,);
  2026 
  2027     if (window->flags & SDL_WINDOW_SHOWN) {
  2028         return;
  2029     }
  2030 
  2031     if (_this->ShowWindow) {
  2032         _this->ShowWindow(_this, window);
  2033     }
  2034     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  2035 }
  2036 
  2037 void
  2038 SDL_HideWindow(SDL_Window * window)
  2039 {
  2040     CHECK_WINDOW_MAGIC(window,);
  2041 
  2042     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  2043         return;
  2044     }
  2045 
  2046 	window->is_hiding = SDL_TRUE;
  2047     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2048 
  2049     if (_this->HideWindow) {
  2050         _this->HideWindow(_this, window);
  2051     }
  2052 	window->is_hiding = SDL_FALSE;
  2053     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  2054 }
  2055 
  2056 void
  2057 SDL_RaiseWindow(SDL_Window * window)
  2058 {
  2059     CHECK_WINDOW_MAGIC(window,);
  2060 
  2061     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  2062         return;
  2063     }
  2064     if (_this->RaiseWindow) {
  2065         _this->RaiseWindow(_this, window);
  2066     }
  2067 }
  2068 
  2069 void
  2070 SDL_MaximizeWindow(SDL_Window * window)
  2071 {
  2072     CHECK_WINDOW_MAGIC(window,);
  2073 
  2074     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  2075         return;
  2076     }
  2077 
  2078     /* !!! FIXME: should this check if the window is resizable? */
  2079 
  2080     if (_this->MaximizeWindow) {
  2081         _this->MaximizeWindow(_this, window);
  2082     }
  2083 }
  2084 
  2085 void
  2086 SDL_MinimizeWindow(SDL_Window * window)
  2087 {
  2088     CHECK_WINDOW_MAGIC(window,);
  2089 
  2090     if (window->flags & SDL_WINDOW_MINIMIZED) {
  2091         return;
  2092     }
  2093 
  2094     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2095 
  2096     if (_this->MinimizeWindow) {
  2097         _this->MinimizeWindow(_this, window);
  2098     }
  2099 }
  2100 
  2101 void
  2102 SDL_RestoreWindow(SDL_Window * window)
  2103 {
  2104     CHECK_WINDOW_MAGIC(window,);
  2105 
  2106     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  2107         return;
  2108     }
  2109 
  2110     if (_this->RestoreWindow) {
  2111         _this->RestoreWindow(_this, window);
  2112     }
  2113 }
  2114 
  2115 int
  2116 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  2117 {
  2118     Uint32 oldflags;
  2119     CHECK_WINDOW_MAGIC(window, -1);
  2120 
  2121     flags &= FULLSCREEN_MASK;
  2122 
  2123     if (flags == (window->flags & FULLSCREEN_MASK)) {
  2124         return 0;
  2125     }
  2126 
  2127     /* clear the previous flags and OR in the new ones */
  2128     oldflags = window->flags & FULLSCREEN_MASK;
  2129     window->flags &= ~FULLSCREEN_MASK;
  2130     window->flags |= flags;
  2131 
  2132     if (SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)) == 0) {
  2133         return 0;
  2134     }
  2135     
  2136     window->flags &= ~FULLSCREEN_MASK;
  2137     window->flags |= oldflags;
  2138     return -1;
  2139 }
  2140 
  2141 static SDL_Surface *
  2142 SDL_CreateWindowFramebuffer(SDL_Window * window)
  2143 {
  2144     Uint32 format;
  2145     void *pixels;
  2146     int pitch;
  2147     int bpp;
  2148     Uint32 Rmask, Gmask, Bmask, Amask;
  2149 
  2150     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  2151         return NULL;
  2152     }
  2153 
  2154     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  2155         return NULL;
  2156     }
  2157 
  2158     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  2159         return NULL;
  2160     }
  2161 
  2162     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  2163 }
  2164 
  2165 SDL_Surface *
  2166 SDL_GetWindowSurface(SDL_Window * window)
  2167 {
  2168     CHECK_WINDOW_MAGIC(window, NULL);
  2169 
  2170     if (!window->surface_valid) {
  2171         if (window->surface) {
  2172             window->surface->flags &= ~SDL_DONTFREE;
  2173             SDL_FreeSurface(window->surface);
  2174         }
  2175         window->surface = SDL_CreateWindowFramebuffer(window);
  2176         if (window->surface) {
  2177             window->surface_valid = SDL_TRUE;
  2178             window->surface->flags |= SDL_DONTFREE;
  2179         }
  2180     }
  2181     return window->surface;
  2182 }
  2183 
  2184 int
  2185 SDL_UpdateWindowSurface(SDL_Window * window)
  2186 {
  2187     SDL_Rect full_rect;
  2188 
  2189     CHECK_WINDOW_MAGIC(window, -1);
  2190 
  2191     full_rect.x = 0;
  2192     full_rect.y = 0;
  2193     full_rect.w = window->w;
  2194     full_rect.h = window->h;
  2195     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  2196 }
  2197 
  2198 int
  2199 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  2200                              int numrects)
  2201 {
  2202     CHECK_WINDOW_MAGIC(window, -1);
  2203 
  2204     if (!window->surface_valid) {
  2205         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  2206     }
  2207 
  2208     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  2209 }
  2210 
  2211 int
  2212 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  2213 {
  2214     Uint16 ramp[256];
  2215     int status;
  2216 
  2217     CHECK_WINDOW_MAGIC(window, -1);
  2218 
  2219     SDL_CalculateGammaRamp(brightness, ramp);
  2220     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  2221     if (status == 0) {
  2222         window->brightness = brightness;
  2223     }
  2224     return status;
  2225 }
  2226 
  2227 float
  2228 SDL_GetWindowBrightness(SDL_Window * window)
  2229 {
  2230     CHECK_WINDOW_MAGIC(window, 1.0f);
  2231 
  2232     return window->brightness;
  2233 }
  2234 
  2235 int
  2236 SDL_SetWindowOpacity(SDL_Window * window, float opacity)
  2237 {
  2238     int retval;
  2239     CHECK_WINDOW_MAGIC(window, -1);
  2240 
  2241     if (!_this->SetWindowOpacity) {
  2242         return SDL_Unsupported();
  2243     }
  2244 
  2245     if (opacity < 0.0f) {
  2246         opacity = 0.0f;
  2247     } else if (opacity > 1.0f) {
  2248         opacity = 1.0f;
  2249     }
  2250 
  2251     retval = _this->SetWindowOpacity(_this, window, opacity);
  2252     if (retval == 0) {
  2253         window->opacity = opacity;
  2254     }
  2255 
  2256     return retval;
  2257 }
  2258 
  2259 int
  2260 SDL_GetWindowOpacity(SDL_Window * window, float * out_opacity)
  2261 {
  2262     CHECK_WINDOW_MAGIC(window, -1);
  2263 
  2264     if (out_opacity) {
  2265         *out_opacity = window->opacity;
  2266     }
  2267 
  2268     return 0;
  2269 }
  2270 
  2271 int
  2272 SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window)
  2273 {
  2274     CHECK_WINDOW_MAGIC(modal_window, -1);
  2275     CHECK_WINDOW_MAGIC(parent_window, -1);
  2276 
  2277     if (!_this->SetWindowModalFor) {
  2278         return SDL_Unsupported();
  2279     }
  2280     
  2281     return _this->SetWindowModalFor(_this, modal_window, parent_window);
  2282 }
  2283 
  2284 int 
  2285 SDL_SetWindowInputFocus(SDL_Window * window)
  2286 {
  2287     CHECK_WINDOW_MAGIC(window, -1);
  2288 
  2289     if (!_this->SetWindowInputFocus) {
  2290         return SDL_Unsupported();
  2291     }
  2292     
  2293     return _this->SetWindowInputFocus(_this, window);
  2294 }
  2295 
  2296 
  2297 int
  2298 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  2299                                             const Uint16 * green,
  2300                                             const Uint16 * blue)
  2301 {
  2302     CHECK_WINDOW_MAGIC(window, -1);
  2303 
  2304     if (!_this->SetWindowGammaRamp) {
  2305         return SDL_Unsupported();
  2306     }
  2307 
  2308     if (!window->gamma) {
  2309         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  2310             return -1;
  2311         }
  2312         SDL_assert(window->gamma != NULL);
  2313     }
  2314 
  2315     if (red) {
  2316         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  2317     }
  2318     if (green) {
  2319         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  2320     }
  2321     if (blue) {
  2322         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  2323     }
  2324     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2325         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  2326     } else {
  2327         return 0;
  2328     }
  2329 }
  2330 
  2331 int
  2332 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  2333                                             Uint16 * green,
  2334                                             Uint16 * blue)
  2335 {
  2336     CHECK_WINDOW_MAGIC(window, -1);
  2337 
  2338     if (!window->gamma) {
  2339         int i;
  2340 
  2341         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  2342         if (!window->gamma) {
  2343             return SDL_OutOfMemory();
  2344         }
  2345         window->saved_gamma = window->gamma + 3*256;
  2346 
  2347         if (_this->GetWindowGammaRamp) {
  2348             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  2349                 return -1;
  2350             }
  2351         } else {
  2352             /* Create an identity gamma ramp */
  2353             for (i = 0; i < 256; ++i) {
  2354                 Uint16 value = (Uint16)((i << 8) | i);
  2355 
  2356                 window->gamma[0*256+i] = value;
  2357                 window->gamma[1*256+i] = value;
  2358                 window->gamma[2*256+i] = value;
  2359             }
  2360         }
  2361         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  2362     }
  2363 
  2364     if (red) {
  2365         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  2366     }
  2367     if (green) {
  2368         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  2369     }
  2370     if (blue) {
  2371         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  2372     }
  2373     return 0;
  2374 }
  2375 
  2376 void
  2377 SDL_UpdateWindowGrab(SDL_Window * window)
  2378 {
  2379     SDL_Window *grabbed_window;
  2380     SDL_bool grabbed;
  2381     if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
  2382          (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  2383         grabbed = SDL_TRUE;
  2384     } else {
  2385         grabbed = SDL_FALSE;
  2386     }
  2387 
  2388     grabbed_window = _this->grabbed_window;
  2389     if (grabbed) {
  2390         if (grabbed_window && (grabbed_window != window)) {
  2391             /* stealing a grab from another window! */
  2392             grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2393             if (_this->SetWindowGrab) {
  2394                 _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE);
  2395             }
  2396         }
  2397         _this->grabbed_window = window;
  2398     } else if (grabbed_window == window) {
  2399         _this->grabbed_window = NULL;  /* ungrabbing. */
  2400     }
  2401 
  2402     if (_this->SetWindowGrab) {
  2403         _this->SetWindowGrab(_this, window, grabbed);
  2404     }
  2405 }
  2406 
  2407 void
  2408 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  2409 {
  2410     CHECK_WINDOW_MAGIC(window,);
  2411 
  2412     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  2413         return;
  2414     }
  2415     if (grabbed) {
  2416         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  2417     } else {
  2418         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2419     }
  2420     SDL_UpdateWindowGrab(window);
  2421 }
  2422 
  2423 SDL_bool
  2424 SDL_GetWindowGrab(SDL_Window * window)
  2425 {
  2426     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2427     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
  2428     return window == _this->grabbed_window;
  2429 }
  2430 
  2431 SDL_Window *
  2432 SDL_GetGrabbedWindow(void)
  2433 {
  2434     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
  2435     return _this->grabbed_window;
  2436 }
  2437 
  2438 void
  2439 SDL_OnWindowShown(SDL_Window * window)
  2440 {
  2441     SDL_OnWindowRestored(window);
  2442 }
  2443 
  2444 void
  2445 SDL_OnWindowHidden(SDL_Window * window)
  2446 {
  2447     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2448 }
  2449 
  2450 void
  2451 SDL_OnWindowResized(SDL_Window * window)
  2452 {
  2453     window->surface_valid = SDL_FALSE;
  2454     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2455 }
  2456 
  2457 void
  2458 SDL_OnWindowMinimized(SDL_Window * window)
  2459 {
  2460     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2461 }
  2462 
  2463 void
  2464 SDL_OnWindowRestored(SDL_Window * window)
  2465 {
  2466     /*
  2467      * FIXME: Is this fine to just remove this, or should it be preserved just
  2468      * for the fullscreen case? In principle it seems like just hiding/showing
  2469      * windows shouldn't affect the stacking order; maybe the right fix is to
  2470      * re-decouple OnWindowShown and OnWindowRestored.
  2471      */
  2472     /*SDL_RaiseWindow(window);*/
  2473 
  2474     if (FULLSCREEN_VISIBLE(window)) {
  2475         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2476     }
  2477 }
  2478 
  2479 void
  2480 SDL_OnWindowEnter(SDL_Window * window)
  2481 {
  2482     if (_this->OnWindowEnter) {
  2483         _this->OnWindowEnter(_this, window);
  2484     }
  2485 }
  2486 
  2487 void
  2488 SDL_OnWindowLeave(SDL_Window * window)
  2489 {
  2490 }
  2491 
  2492 void
  2493 SDL_OnWindowFocusGained(SDL_Window * window)
  2494 {
  2495     SDL_Mouse *mouse = SDL_GetMouse();
  2496 
  2497     if (window->gamma && _this->SetWindowGammaRamp) {
  2498         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2499     }
  2500 
  2501     if (mouse && mouse->relative_mode) {
  2502         SDL_SetMouseFocus(window);
  2503         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2504     }
  2505 
  2506     SDL_UpdateWindowGrab(window);
  2507 }
  2508 
  2509 static SDL_bool
  2510 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2511 {
  2512     const char *hint;
  2513 
  2514     if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
  2515         return SDL_FALSE;
  2516     }
  2517 
  2518 #ifdef __MACOSX__
  2519     if (Cocoa_IsWindowInFullscreenSpace(window)) {
  2520         return SDL_FALSE;
  2521     }
  2522 #endif
  2523 
  2524     hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2525     if (hint) {
  2526         if (*hint == '0') {
  2527             return SDL_FALSE;
  2528         } else {
  2529             return SDL_TRUE;
  2530         }
  2531     }
  2532 
  2533     return SDL_TRUE;
  2534 }
  2535 
  2536 void
  2537 SDL_OnWindowFocusLost(SDL_Window * window)
  2538 {
  2539     if (window->gamma && _this->SetWindowGammaRamp) {
  2540         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2541     }
  2542 
  2543     SDL_UpdateWindowGrab(window);
  2544 
  2545     if (ShouldMinimizeOnFocusLoss(window)) {
  2546         SDL_MinimizeWindow(window);
  2547     }
  2548 }
  2549 
  2550 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
  2551    !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
  2552 SDL_Window *
  2553 SDL_GetFocusWindow(void)
  2554 {
  2555     SDL_Window *window;
  2556 
  2557     if (!_this) {
  2558         return NULL;
  2559     }
  2560     for (window = _this->windows; window; window = window->next) {
  2561         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2562             return window;
  2563         }
  2564     }
  2565     return NULL;
  2566 }
  2567 
  2568 void
  2569 SDL_DestroyWindow(SDL_Window * window)
  2570 {
  2571     SDL_VideoDisplay *display;
  2572 
  2573     CHECK_WINDOW_MAGIC(window,);
  2574 
  2575     window->is_destroying = SDL_TRUE;
  2576 
  2577     /* Restore video mode, etc. */
  2578     SDL_HideWindow(window);
  2579 
  2580     /* Make sure this window no longer has focus */
  2581     if (SDL_GetKeyboardFocus() == window) {
  2582         SDL_SetKeyboardFocus(NULL);
  2583     }
  2584     if (SDL_GetMouseFocus() == window) {
  2585         SDL_SetMouseFocus(NULL);
  2586     }
  2587 
  2588     /* make no context current if this is the current context window. */
  2589     if (window->flags & SDL_WINDOW_OPENGL) {
  2590         if (_this->current_glwin == window) {
  2591             SDL_GL_MakeCurrent(window, NULL);
  2592         }
  2593     }
  2594 
  2595     if (window->surface) {
  2596         window->surface->flags &= ~SDL_DONTFREE;
  2597         SDL_FreeSurface(window->surface);
  2598     }
  2599     if (_this->DestroyWindowFramebuffer) {
  2600         _this->DestroyWindowFramebuffer(_this, window);
  2601     }
  2602     if (_this->DestroyWindow) {
  2603         _this->DestroyWindow(_this, window);
  2604     }
  2605     if (window->flags & SDL_WINDOW_OPENGL) {
  2606         SDL_GL_UnloadLibrary();
  2607     }
  2608 
  2609     display = SDL_GetDisplayForWindow(window);
  2610     if (display->fullscreen_window == window) {
  2611         display->fullscreen_window = NULL;
  2612     }
  2613 
  2614     /* Now invalidate magic */
  2615     window->magic = NULL;
  2616 
  2617     /* Free memory associated with the window */
  2618     SDL_free(window->title);
  2619     SDL_FreeSurface(window->icon);
  2620     SDL_free(window->gamma);
  2621     while (window->data) {
  2622         SDL_WindowUserData *data = window->data;
  2623 
  2624         window->data = data->next;
  2625         SDL_free(data->name);
  2626         SDL_free(data);
  2627     }
  2628 
  2629     /* Unlink the window from the list */
  2630     if (window->next) {
  2631         window->next->prev = window->prev;
  2632     }
  2633     if (window->prev) {
  2634         window->prev->next = window->next;
  2635     } else {
  2636         _this->windows = window->next;
  2637     }
  2638 
  2639     SDL_free(window);
  2640 }
  2641 
  2642 SDL_bool
  2643 SDL_IsScreenSaverEnabled()
  2644 {
  2645     if (!_this) {
  2646         return SDL_TRUE;
  2647     }
  2648     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2649 }
  2650 
  2651 void
  2652 SDL_EnableScreenSaver()
  2653 {
  2654     if (!_this) {
  2655         return;
  2656     }
  2657     if (!_this->suspend_screensaver) {
  2658         return;
  2659     }
  2660     _this->suspend_screensaver = SDL_FALSE;
  2661     if (_this->SuspendScreenSaver) {
  2662         _this->SuspendScreenSaver(_this);
  2663     }
  2664 }
  2665 
  2666 void
  2667 SDL_DisableScreenSaver()
  2668 {
  2669     if (!_this) {
  2670         return;
  2671     }
  2672     if (_this->suspend_screensaver) {
  2673         return;
  2674     }
  2675     _this->suspend_screensaver = SDL_TRUE;
  2676     if (_this->SuspendScreenSaver) {
  2677         _this->SuspendScreenSaver(_this);
  2678     }
  2679 }
  2680 
  2681 void
  2682 SDL_VideoQuit(void)
  2683 {
  2684     int i, j;
  2685 
  2686     if (!_this) {
  2687         return;
  2688     }
  2689 
  2690     /* Halt event processing before doing anything else */
  2691     SDL_TouchQuit();
  2692     SDL_MouseQuit();
  2693     SDL_KeyboardQuit();
  2694     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2695 
  2696     SDL_EnableScreenSaver();
  2697 
  2698     /* Clean up the system video */
  2699     while (_this->windows) {
  2700         SDL_DestroyWindow(_this->windows);
  2701     }
  2702     _this->VideoQuit(_this);
  2703 
  2704     for (i = 0; i < _this->num_displays; ++i) {
  2705         SDL_VideoDisplay *display = &_this->displays[i];
  2706         for (j = display->num_display_modes; j--;) {
  2707             SDL_free(display->display_modes[j].driverdata);
  2708             display->display_modes[j].driverdata = NULL;
  2709         }
  2710         SDL_free(display->display_modes);
  2711         display->display_modes = NULL;
  2712         SDL_free(display->desktop_mode.driverdata);
  2713         display->desktop_mode.driverdata = NULL;
  2714         SDL_free(display->driverdata);
  2715         display->driverdata = NULL;
  2716     }
  2717     if (_this->displays) {
  2718         for (i = 0; i < _this->num_displays; ++i) {
  2719             SDL_free(_this->displays[i].name);
  2720         }
  2721         SDL_free(_this->displays);
  2722         _this->displays = NULL;
  2723         _this->num_displays = 0;
  2724     }
  2725     SDL_free(_this->clipboard_text);
  2726     _this->clipboard_text = NULL;
  2727     _this->free(_this);
  2728     _this = NULL;
  2729 }
  2730 
  2731 int
  2732 SDL_GL_LoadLibrary(const char *path)
  2733 {
  2734     int retval;
  2735 
  2736     if (!_this) {
  2737         return SDL_UninitializedVideo();
  2738     }
  2739     if (_this->gl_config.driver_loaded) {
  2740         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2741             return SDL_SetError("OpenGL library already loaded");
  2742         }
  2743         retval = 0;
  2744     } else {
  2745         if (!_this->GL_LoadLibrary) {
  2746             return SDL_SetError("No dynamic GL support in video driver");
  2747         }
  2748         retval = _this->GL_LoadLibrary(_this, path);
  2749     }
  2750     if (retval == 0) {
  2751         ++_this->gl_config.driver_loaded;
  2752     } else {
  2753         if (_this->GL_UnloadLibrary) {
  2754             _this->GL_UnloadLibrary(_this);
  2755         }
  2756     }
  2757     return (retval);
  2758 }
  2759 
  2760 void *
  2761 SDL_GL_GetProcAddress(const char *proc)
  2762 {
  2763     void *func;
  2764 
  2765     if (!_this) {
  2766         SDL_UninitializedVideo();
  2767         return NULL;
  2768     }
  2769     func = NULL;
  2770     if (_this->GL_GetProcAddress) {
  2771         if (_this->gl_config.driver_loaded) {
  2772             func = _this->GL_GetProcAddress(_this, proc);
  2773         } else {
  2774             SDL_SetError("No GL driver has been loaded");
  2775         }
  2776     } else {
  2777         SDL_SetError("No dynamic GL support in video driver");
  2778     }
  2779     return func;
  2780 }
  2781 
  2782 void
  2783 SDL_GL_UnloadLibrary(void)
  2784 {
  2785     if (!_this) {
  2786         SDL_UninitializedVideo();
  2787         return;
  2788     }
  2789     if (_this->gl_config.driver_loaded > 0) {
  2790         if (--_this->gl_config.driver_loaded > 0) {
  2791             return;
  2792         }
  2793         if (_this->GL_UnloadLibrary) {
  2794             _this->GL_UnloadLibrary(_this);
  2795         }
  2796     }
  2797 }
  2798 
  2799 static SDL_INLINE SDL_bool
  2800 isAtLeastGL3(const char *verstr)
  2801 {
  2802     return (verstr && (SDL_atoi(verstr) >= 3));
  2803 }
  2804 
  2805 SDL_bool
  2806 SDL_GL_ExtensionSupported(const char *extension)
  2807 {
  2808 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2809     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2810     const char *extensions;
  2811     const char *start;
  2812     const char *where, *terminator;
  2813 
  2814     /* Extension names should not have spaces. */
  2815     where = SDL_strchr(extension, ' ');
  2816     if (where || *extension == '\0') {
  2817         return SDL_FALSE;
  2818     }
  2819     /* See if there's an environment variable override */
  2820     start = SDL_getenv(extension);
  2821     if (start && *start == '0') {
  2822         return SDL_FALSE;
  2823     }
  2824 
  2825     /* Lookup the available extensions */
  2826 
  2827     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2828     if (!glGetStringFunc) {
  2829         return SDL_FALSE;
  2830     }
  2831 
  2832     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2833         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2834         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2835         GLint num_exts = 0;
  2836         GLint i;
  2837 
  2838         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2839         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2840         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2841             return SDL_FALSE;
  2842         }
  2843 
  2844         #ifndef GL_NUM_EXTENSIONS
  2845         #define GL_NUM_EXTENSIONS 0x821D
  2846         #endif
  2847         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2848         for (i = 0; i < num_exts; i++) {
  2849             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2850             if (SDL_strcmp(thisext, extension) == 0) {
  2851                 return SDL_TRUE;
  2852             }
  2853         }
  2854 
  2855         return SDL_FALSE;
  2856     }
  2857 
  2858     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2859 
  2860     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2861     if (!extensions) {
  2862         return SDL_FALSE;
  2863     }
  2864     /*
  2865      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2866      * extensions string. Don't be fooled by sub-strings, etc.
  2867      */
  2868 
  2869     start = extensions;
  2870 
  2871     for (;;) {
  2872         where = SDL_strstr(start, extension);
  2873         if (!where)
  2874             break;
  2875 
  2876         terminator = where + SDL_strlen(extension);
  2877         if (where == start || *(where - 1) == ' ')
  2878             if (*terminator == ' ' || *terminator == '\0')
  2879                 return SDL_TRUE;
  2880 
  2881         start = terminator;
  2882     }
  2883     return SDL_FALSE;
  2884 #else
  2885     return SDL_FALSE;
  2886 #endif
  2887 }
  2888 
  2889 void
  2890 SDL_GL_ResetAttributes()
  2891 {
  2892     if (!_this) {
  2893         return;
  2894     }
  2895 
  2896     _this->gl_config.red_size = 3;
  2897     _this->gl_config.green_size = 3;
  2898     _this->gl_config.blue_size = 2;
  2899     _this->gl_config.alpha_size = 0;
  2900     _this->gl_config.buffer_size = 0;
  2901     _this->gl_config.depth_size = 16;
  2902     _this->gl_config.stencil_size = 0;
  2903     _this->gl_config.double_buffer = 1;
  2904     _this->gl_config.accum_red_size = 0;
  2905     _this->gl_config.accum_green_size = 0;
  2906     _this->gl_config.accum_blue_size = 0;
  2907     _this->gl_config.accum_alpha_size = 0;
  2908     _this->gl_config.stereo = 0;
  2909     _this->gl_config.multisamplebuffers = 0;
  2910     _this->gl_config.multisamplesamples = 0;
  2911     _this->gl_config.retained_backing = 1;
  2912     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
  2913     _this->gl_config.profile_mask = 0;
  2914 #if SDL_VIDEO_OPENGL
  2915     _this->gl_config.major_version = 2;
  2916     _this->gl_config.minor_version = 1;
  2917 #elif SDL_VIDEO_OPENGL_ES2
  2918     _this->gl_config.major_version = 2;
  2919     _this->gl_config.minor_version = 0;
  2920     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2921 #elif SDL_VIDEO_OPENGL_ES
  2922     _this->gl_config.major_version = 1;
  2923     _this->gl_config.minor_version = 1;
  2924     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2925 #endif
  2926     _this->gl_config.flags = 0;
  2927     _this->gl_config.framebuffer_srgb_capable = 0;
  2928     _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
  2929 
  2930     _this->gl_config.share_with_current_context = 0;
  2931 }
  2932 
  2933 int
  2934 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2935 {
  2936 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2937     int retval;
  2938 
  2939     if (!_this) {
  2940         return SDL_UninitializedVideo();
  2941     }
  2942     retval = 0;
  2943     switch (attr) {
  2944     case SDL_GL_RED_SIZE:
  2945         _this->gl_config.red_size = value;
  2946         break;
  2947     case SDL_GL_GREEN_SIZE:
  2948         _this->gl_config.green_size = value;
  2949         break;
  2950     case SDL_GL_BLUE_SIZE:
  2951         _this->gl_config.blue_size = value;
  2952         break;
  2953     case SDL_GL_ALPHA_SIZE:
  2954         _this->gl_config.alpha_size = value;
  2955         break;
  2956     case SDL_GL_DOUBLEBUFFER:
  2957         _this->gl_config.double_buffer = value;
  2958         break;
  2959     case SDL_GL_BUFFER_SIZE:
  2960         _this->gl_config.buffer_size = value;
  2961         break;
  2962     case SDL_GL_DEPTH_SIZE:
  2963         _this->gl_config.depth_size = value;
  2964         break;
  2965     case SDL_GL_STENCIL_SIZE:
  2966         _this->gl_config.stencil_size = value;
  2967         break;
  2968     case SDL_GL_ACCUM_RED_SIZE:
  2969         _this->gl_config.accum_red_size = value;
  2970         break;
  2971     case SDL_GL_ACCUM_GREEN_SIZE:
  2972         _this->gl_config.accum_green_size = value;
  2973         break;
  2974     case SDL_GL_ACCUM_BLUE_SIZE:
  2975         _this->gl_config.accum_blue_size = value;
  2976         break;
  2977     case SDL_GL_ACCUM_ALPHA_SIZE:
  2978         _this->gl_config.accum_alpha_size = value;
  2979         break;
  2980     case SDL_GL_STEREO:
  2981         _this->gl_config.stereo = value;
  2982         break;
  2983     case SDL_GL_MULTISAMPLEBUFFERS:
  2984         _this->gl_config.multisamplebuffers = value;
  2985         break;
  2986     case SDL_GL_MULTISAMPLESAMPLES:
  2987         _this->gl_config.multisamplesamples = value;
  2988         break;
  2989     case SDL_GL_ACCELERATED_VISUAL:
  2990         _this->gl_config.accelerated = value;
  2991         break;
  2992     case SDL_GL_RETAINED_BACKING:
  2993         _this->gl_config.retained_backing = value;
  2994         break;
  2995     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2996         _this->gl_config.major_version = value;
  2997         break;
  2998     case SDL_GL_CONTEXT_MINOR_VERSION:
  2999         _this->gl_config.minor_version = value;
  3000         break;
  3001     case SDL_GL_CONTEXT_EGL:
  3002         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  3003         if (value != 0) {
  3004             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  3005         } else {
  3006             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  3007         };
  3008         break;
  3009     case SDL_GL_CONTEXT_FLAGS:
  3010         if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  3011                       SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  3012                       SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  3013                       SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
  3014             retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  3015             break;
  3016         }
  3017         _this->gl_config.flags = value;
  3018         break;
  3019     case SDL_GL_CONTEXT_PROFILE_MASK:
  3020         if (value != 0 &&
  3021             value != SDL_GL_CONTEXT_PROFILE_CORE &&
  3022             value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  3023             value != SDL_GL_CONTEXT_PROFILE_ES) {
  3024             retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  3025             break;
  3026         }
  3027         _this->gl_config.profile_mask = value;
  3028         break;
  3029     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  3030         _this->gl_config.share_with_current_context = value;
  3031         break;
  3032     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  3033         _this->gl_config.framebuffer_srgb_capable = value;
  3034         break;
  3035     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
  3036         _this->gl_config.release_behavior = value;
  3037         break;
  3038     default:
  3039         retval = SDL_SetError("Unknown OpenGL attribute");
  3040         break;
  3041     }
  3042     return retval;
  3043 #else
  3044     return SDL_Unsupported();
  3045 #endif /* SDL_VIDEO_OPENGL */
  3046 }
  3047 
  3048 int
  3049 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  3050 {
  3051 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  3052     GLenum (APIENTRY *glGetErrorFunc) (void);
  3053     GLenum attrib = 0;
  3054     GLenum error = 0;
  3055 
  3056     /*
  3057      * Some queries in Core Profile desktop OpenGL 3+ contexts require
  3058      * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that
  3059      * the enums we use for the former function don't exist in OpenGL ES 2, and
  3060      * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2.
  3061      */
  3062 #if SDL_VIDEO_OPENGL
  3063     const GLubyte *(APIENTRY *glGetStringFunc) (GLenum name);
  3064     void (APIENTRY *glGetFramebufferAttachmentParameterivFunc) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
  3065     GLenum attachment = GL_BACK_LEFT;
  3066     GLenum attachmentattrib = 0;
  3067 #endif
  3068 
  3069     /* Clear value in any case */
  3070     *value = 0;
  3071 
  3072     switch (attr) {
  3073     case SDL_GL_RED_SIZE:
  3074 #if SDL_VIDEO_OPENGL
  3075         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
  3076 #endif
  3077         attrib = GL_RED_BITS;
  3078         break;
  3079     case SDL_GL_BLUE_SIZE:
  3080 #if SDL_VIDEO_OPENGL
  3081         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
  3082 #endif
  3083         attrib = GL_BLUE_BITS;
  3084         break;
  3085     case SDL_GL_GREEN_SIZE:
  3086 #if SDL_VIDEO_OPENGL
  3087         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
  3088 #endif
  3089         attrib = GL_GREEN_BITS;
  3090         break;
  3091     case SDL_GL_ALPHA_SIZE:
  3092 #if SDL_VIDEO_OPENGL
  3093         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
  3094 #endif
  3095         attrib = GL_ALPHA_BITS;
  3096         break;
  3097     case SDL_GL_DOUBLEBUFFER:
  3098 #if SDL_VIDEO_OPENGL
  3099         attrib = GL_DOUBLEBUFFER;
  3100         break;
  3101 #else
  3102         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  3103         /* parameter which switches double buffer to single buffer. OpenGL ES */
  3104         /* SDL driver must set proper value after initialization              */
  3105         *value = _this->gl_config.double_buffer;
  3106         return 0;
  3107 #endif
  3108     case SDL_GL_DEPTH_SIZE:
  3109 #if SDL_VIDEO_OPENGL
  3110         attachment = GL_DEPTH;
  3111         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE;
  3112 #endif
  3113         attrib = GL_DEPTH_BITS;
  3114         break;
  3115     case SDL_GL_STENCIL_SIZE:
  3116 #if SDL_VIDEO_OPENGL
  3117         attachment = GL_STENCIL;
  3118         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE;
  3119 #endif
  3120         attrib = GL_STENCIL_BITS;
  3121         break;
  3122 #if SDL_VIDEO_OPENGL
  3123     case SDL_GL_ACCUM_RED_SIZE:
  3124         attrib = GL_ACCUM_RED_BITS;
  3125         break;
  3126     case SDL_GL_ACCUM_GREEN_SIZE:
  3127         attrib = GL_ACCUM_GREEN_BITS;
  3128         break;
  3129     case SDL_GL_ACCUM_BLUE_SIZE:
  3130         attrib = GL_ACCUM_BLUE_BITS;
  3131         break;
  3132     case SDL_GL_ACCUM_ALPHA_SIZE:
  3133         attrib = GL_ACCUM_ALPHA_BITS;
  3134         break;
  3135     case SDL_GL_STEREO:
  3136         attrib = GL_STEREO;
  3137         break;
  3138 #else
  3139     case SDL_GL_ACCUM_RED_SIZE:
  3140     case SDL_GL_ACCUM_GREEN_SIZE:
  3141     case SDL_GL_ACCUM_BLUE_SIZE:
  3142     case SDL_GL_ACCUM_ALPHA_SIZE:
  3143     case SDL_GL_STEREO:
  3144         /* none of these are supported in OpenGL ES */
  3145         *value = 0;
  3146         return 0;
  3147 #endif
  3148     case SDL_GL_MULTISAMPLEBUFFERS:
  3149         attrib = GL_SAMPLE_BUFFERS;
  3150         break;
  3151     case SDL_GL_MULTISAMPLESAMPLES:
  3152         attrib = GL_SAMPLES;
  3153         break;
  3154     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
  3155 #if SDL_VIDEO_OPENGL
  3156         attrib = GL_CONTEXT_RELEASE_BEHAVIOR;
  3157 #else
  3158         attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR;
  3159 #endif
  3160         break;
  3161     case SDL_GL_BUFFER_SIZE:
  3162         {
  3163             int rsize = 0, gsize = 0, bsize = 0, asize = 0;
  3164 
  3165             /* There doesn't seem to be a single flag in OpenGL for this! */
  3166             if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize) < 0) {
  3167                 return -1;
  3168             }
  3169             if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize) < 0) {
  3170                 return -1;
  3171             }
  3172             if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize) < 0) {
  3173                 return -1;
  3174             }
  3175             if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize) < 0) {
  3176                 return -1;
  3177             }
  3178 
  3179             *value = rsize + gsize + bsize + asize;
  3180             return 0;
  3181         }
  3182     case SDL_GL_ACCELERATED_VISUAL:
  3183         {
  3184             /* FIXME: How do we get this information? */
  3185             *value = (_this->gl_config.accelerated != 0);
  3186             return 0;
  3187         }
  3188     case SDL_GL_RETAINED_BACKING:
  3189         {
  3190             *value = _this->gl_config.retained_backing;
  3191             return 0;
  3192         }
  3193     case SDL_GL_CONTEXT_MAJOR_VERSION:
  3194         {
  3195             *value = _this->gl_config.major_version;
  3196             return 0;
  3197         }
  3198     case SDL_GL_CONTEXT_MINOR_VERSION:
  3199         {
  3200             *value = _this->gl_config.minor_version;
  3201             return 0;
  3202         }
  3203     case SDL_GL_CONTEXT_EGL:
  3204         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  3205         {
  3206             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  3207                 *value = 1;
  3208             }
  3209             else {
  3210                 *value = 0;
  3211             }
  3212             return 0;
  3213         }
  3214     case SDL_GL_CONTEXT_FLAGS:
  3215         {
  3216             *value = _this->gl_config.flags;
  3217             return 0;
  3218         }
  3219     case SDL_GL_CONTEXT_PROFILE_MASK:
  3220         {
  3221             *value = _this->gl_config.profile_mask;
  3222             return 0;
  3223         }
  3224     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  3225         {
  3226             *value = _this->gl_config.share_with_current_context;
  3227             return 0;
  3228         }
  3229     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  3230         {
  3231             *value = _this->gl_config.framebuffer_srgb_capable;
  3232             return 0;
  3233         }
  3234     default:
  3235         return SDL_SetError("Unknown OpenGL attribute");
  3236     }
  3237 
  3238 #if SDL_VIDEO_OPENGL
  3239     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  3240     if (!glGetStringFunc) {
  3241         return SDL_SetError("Failed getting OpenGL glGetString entry point");
  3242     }
  3243 
  3244     if (attachmentattrib && isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  3245         glGetFramebufferAttachmentParameterivFunc = SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv");
  3246 
  3247         if (glGetFramebufferAttachmentParameterivFunc) {
  3248             glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *) value);
  3249         } else {
  3250             return SDL_SetError("Failed getting OpenGL glGetFramebufferAttachmentParameteriv entry point");
  3251         }
  3252     } else
  3253 #endif
  3254     {
  3255         void (APIENTRY *glGetIntegervFunc) (GLenum pname, GLint * params);
  3256         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  3257         if (glGetIntegervFunc) {
  3258             glGetIntegervFunc(attrib, (GLint *) value);
  3259         } else {
  3260             return SDL_SetError("Failed getting OpenGL glGetIntegerv entry point");
  3261         }
  3262     }
  3263 
  3264     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  3265     if (!glGetErrorFunc) {
  3266         return SDL_SetError("Failed getting OpenGL glGetError entry point");
  3267     }
  3268 
  3269     error = glGetErrorFunc();
  3270     if (error != GL_NO_ERROR) {
  3271         if (error == GL_INVALID_ENUM) {
  3272             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  3273         } else if (error == GL_INVALID_VALUE) {
  3274             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  3275         }
  3276         return SDL_SetError("OpenGL error: %08X", error);
  3277     }
  3278     return 0;
  3279 #else
  3280     return SDL_Unsupported();
  3281 #endif /* SDL_VIDEO_OPENGL */
  3282 }
  3283 
  3284 SDL_GLContext
  3285 SDL_GL_CreateContext(SDL_Window * window)
  3286 {
  3287     SDL_GLContext ctx = NULL;
  3288     CHECK_WINDOW_MAGIC(window, NULL);
  3289 
  3290     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3291         SDL_SetError("The specified window isn't an OpenGL window");
  3292         return NULL;
  3293     }
  3294 
  3295     ctx = _this->GL_CreateContext(_this, window);
  3296 
  3297     /* Creating a context is assumed to make it current in the SDL driver. */
  3298     if (ctx) {
  3299         _this->current_glwin = window;
  3300         _this->current_glctx = ctx;
  3301         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  3302         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  3303     }
  3304     return ctx;
  3305 }
  3306 
  3307 int
  3308 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  3309 {
  3310     int retval;
  3311 
  3312     if (window == SDL_GL_GetCurrentWindow() &&
  3313         ctx == SDL_GL_GetCurrentContext()) {
  3314         /* We're already current. */
  3315         return 0;
  3316     }
  3317 
  3318     if (!ctx) {
  3319         window = NULL;
  3320     } else {
  3321         CHECK_WINDOW_MAGIC(window, -1);
  3322 
  3323         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3324             return SDL_SetError("The specified window isn't an OpenGL window");
  3325         }
  3326     }
  3327 
  3328     retval = _this->GL_MakeCurrent(_this, window, ctx);
  3329     if (retval == 0) {
  3330         _this->current_glwin = window;
  3331         _this->current_glctx = ctx;
  3332         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  3333         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  3334     }
  3335     return retval;
  3336 }
  3337 
  3338 SDL_Window *
  3339 SDL_GL_GetCurrentWindow(void)
  3340 {
  3341     if (!_this) {
  3342         SDL_UninitializedVideo();
  3343         return NULL;
  3344     }
  3345     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  3346 }
  3347 
  3348 SDL_GLContext
  3349 SDL_GL_GetCurrentContext(void)
  3350 {
  3351     if (!_this) {
  3352         SDL_UninitializedVideo();
  3353         return NULL;
  3354     }
  3355     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  3356 }
  3357 
  3358 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  3359 {
  3360     CHECK_WINDOW_MAGIC(window,);
  3361 
  3362     if (_this->GL_GetDrawableSize) {
  3363         _this->GL_GetDrawableSize(_this, window, w, h);
  3364     } else {
  3365         SDL_GetWindowSize(window, w, h);
  3366     }
  3367 }
  3368 
  3369 int
  3370 SDL_GL_SetSwapInterval(int interval)
  3371 {
  3372     if (!_this) {
  3373         return SDL_UninitializedVideo();
  3374     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3375         return SDL_SetError("No OpenGL context has been made current");
  3376     } else if (_this->GL_SetSwapInterval) {
  3377         return _this->GL_SetSwapInterval(_this, interval);
  3378     } else {
  3379         return SDL_SetError("Setting the swap interval is not supported");
  3380     }
  3381 }
  3382 
  3383 int
  3384 SDL_GL_GetSwapInterval(void)
  3385 {
  3386     if (!_this) {
  3387         return 0;
  3388     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3389         return 0;
  3390     } else if (_this->GL_GetSwapInterval) {
  3391         return _this->GL_GetSwapInterval(_this);
  3392     } else {
  3393         return 0;
  3394     }
  3395 }
  3396 
  3397 void
  3398 SDL_GL_SwapWindow(SDL_Window * window)
  3399 {
  3400     CHECK_WINDOW_MAGIC(window,);
  3401 
  3402     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3403         SDL_SetError("The specified window isn't an OpenGL window");
  3404         return;
  3405     }
  3406 
  3407     if (SDL_GL_GetCurrentWindow() != window) {
  3408         SDL_SetError("The specified window has not been made current");
  3409         return;
  3410     }
  3411 
  3412     _this->GL_SwapWindow(_this, window);
  3413 }
  3414 
  3415 void
  3416 SDL_GL_DeleteContext(SDL_GLContext context)
  3417 {
  3418     if (!_this || !context) {
  3419         return;
  3420     }
  3421 
  3422     if (SDL_GL_GetCurrentContext() == context) {
  3423         SDL_GL_MakeCurrent(NULL, NULL);
  3424     }
  3425 
  3426     _this->GL_DeleteContext(_this, context);
  3427 }
  3428 
  3429 #if 0                           /* FIXME */
  3430 /*
  3431  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  3432  * & 2 for alpha channel.
  3433  */
  3434 static void
  3435 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  3436 {
  3437     int x, y;
  3438     Uint32 colorkey;
  3439 #define SET_MASKBIT(icon, x, y, mask) \
  3440     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  3441 
  3442     colorkey = icon->format->colorkey;
  3443     switch (icon->format->BytesPerPixel) {
  3444     case 1:
  3445         {
  3446             Uint8 *pixels;
  3447             for (y = 0; y < icon->h; ++y) {
  3448                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  3449                 for (x = 0; x < icon->w; ++x) {
  3450                     if (*pixels++ == colorkey) {
  3451                         SET_MASKBIT(icon, x, y, mask);
  3452                     }
  3453                 }
  3454             }
  3455         }
  3456         break;
  3457 
  3458     case 2:
  3459         {
  3460             Uint16 *pixels;
  3461             for (y = 0; y < icon->h; ++y) {
  3462                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3463                 for (x = 0; x < icon->w; ++x) {
  3464                     if ((flags & 1) && *pixels == colorkey) {
  3465                         SET_MASKBIT(icon, x, y, mask);
  3466                     } else if ((flags & 2)
  3467                                && (*pixels & icon->format->Amask) == 0) {
  3468                         SET_MASKBIT(icon, x, y, mask);
  3469                     }
  3470                     pixels++;
  3471                 }
  3472             }
  3473         }
  3474         break;
  3475 
  3476     case 4:
  3477         {
  3478             Uint32 *pixels;
  3479             for (y = 0; y < icon->h; ++y) {
  3480                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3481                 for (x = 0; x < icon->w; ++x) {
  3482                     if ((flags & 1) && *pixels == colorkey) {
  3483                         SET_MASKBIT(icon, x, y, mask);
  3484                     } else if ((flags & 2)
  3485                                && (*pixels & icon->format->Amask) == 0) {
  3486                         SET_MASKBIT(icon, x, y, mask);
  3487                     }
  3488                     pixels++;
  3489                 }
  3490             }
  3491         }
  3492         break;
  3493     }
  3494 }
  3495 
  3496 /*
  3497  * Sets the window manager icon for the display window.
  3498  */
  3499 void
  3500 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3501 {
  3502     if (icon && _this->SetIcon) {
  3503         /* Generate a mask if necessary, and create the icon! */
  3504         if (mask == NULL) {
  3505             int mask_len = icon->h * (icon->w + 7) / 8;
  3506             int flags = 0;
  3507             mask = (Uint8 *) SDL_malloc(mask_len);
  3508             if (mask == NULL) {
  3509                 return;
  3510             }
  3511             SDL_memset(mask, ~0, mask_len);
  3512             if (icon->flags & SDL_SRCCOLORKEY)
  3513                 flags |= 1;
  3514             if (icon->flags & SDL_SRCALPHA)
  3515                 flags |= 2;
  3516             if (flags) {
  3517                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3518             }
  3519             _this->SetIcon(_this, icon, mask);
  3520             SDL_free(mask);
  3521         } else {
  3522             _this->SetIcon(_this, icon, mask);
  3523         }
  3524     }
  3525 }
  3526 #endif
  3527 
  3528 SDL_bool
  3529 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3530 {
  3531     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3532 
  3533     if (!info) {
  3534         SDL_InvalidParamError("info");
  3535         return SDL_FALSE;
  3536     }
  3537     info->subsystem = SDL_SYSWM_UNKNOWN;
  3538 
  3539     if (!_this->GetWindowWMInfo) {
  3540         SDL_Unsupported();
  3541         return SDL_FALSE;
  3542     }
  3543     return (_this->GetWindowWMInfo(_this, window, info));
  3544 }
  3545 
  3546 void
  3547 SDL_StartTextInput(void)
  3548 {
  3549     SDL_Window *window;
  3550 
  3551     /* First, enable text events */
  3552     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3553     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3554 
  3555     /* Then show the on-screen keyboard, if any */
  3556     window = SDL_GetFocusWindow();
  3557     if (window && _this && _this->ShowScreenKeyboard) {
  3558         _this->ShowScreenKeyboard(_this, window);
  3559     }
  3560 
  3561     /* Finally start the text input system */
  3562     if (_this && _this->StartTextInput) {
  3563         _this->StartTextInput(_this);
  3564     }
  3565 }
  3566 
  3567 SDL_bool
  3568 SDL_IsTextInputActive(void)
  3569 {
  3570     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3571 }
  3572 
  3573 void
  3574 SDL_StopTextInput(void)
  3575 {
  3576     SDL_Window *window;
  3577 
  3578     /* Stop the text input system */
  3579     if (_this && _this->StopTextInput) {
  3580         _this->StopTextInput(_this);
  3581     }
  3582 
  3583     /* Hide the on-screen keyboard, if any */
  3584     window = SDL_GetFocusWindow();
  3585     if (window && _this && _this->HideScreenKeyboard) {
  3586         _this->HideScreenKeyboard(_this, window);
  3587     }
  3588 
  3589     /* Finally disable text events */
  3590     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3591     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3592 }
  3593 
  3594 void
  3595 SDL_SetTextInputRect(SDL_Rect *rect)
  3596 {
  3597     if (_this && _this->SetTextInputRect) {
  3598         _this->SetTextInputRect(_this, rect);
  3599     }
  3600 }
  3601 
  3602 SDL_bool
  3603 SDL_HasScreenKeyboardSupport(void)
  3604 {
  3605     if (_this && _this->HasScreenKeyboardSupport) {
  3606         return _this->HasScreenKeyboardSupport(_this);
  3607     }
  3608     return SDL_FALSE;
  3609 }
  3610 
  3611 SDL_bool
  3612 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3613 {
  3614     if (window && _this && _this->IsScreenKeyboardShown) {
  3615         return _this->IsScreenKeyboardShown(_this, window);
  3616     }
  3617     return SDL_FALSE;
  3618 }
  3619 
  3620 #if SDL_VIDEO_DRIVER_ANDROID
  3621 #include "android/SDL_androidmessagebox.h"
  3622 #endif
  3623 #if SDL_VIDEO_DRIVER_WINDOWS
  3624 #include "windows/SDL_windowsmessagebox.h"
  3625 #endif
  3626 #if SDL_VIDEO_DRIVER_WINRT
  3627 #include "winrt/SDL_winrtmessagebox.h"
  3628 #endif
  3629 #if SDL_VIDEO_DRIVER_COCOA
  3630 #include "cocoa/SDL_cocoamessagebox.h"
  3631 #endif
  3632 #if SDL_VIDEO_DRIVER_UIKIT
  3633 #include "uikit/SDL_uikitmessagebox.h"
  3634 #endif
  3635 #if SDL_VIDEO_DRIVER_X11
  3636 #include "x11/SDL_x11messagebox.h"
  3637 #endif
  3638 
  3639 // This function will be unused if none of the above video drivers are present.
  3640 SDL_UNUSED static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3641 {
  3642     SDL_SysWMinfo info;
  3643     SDL_Window *window = messageboxdata->window;
  3644 
  3645     if (!window) {
  3646         return SDL_TRUE;
  3647     }
  3648 
  3649     SDL_VERSION(&info.version);
  3650     if (!SDL_GetWindowWMInfo(window, &info)) {
  3651         return SDL_TRUE;
  3652     } else {
  3653         return (info.subsystem == drivertype);
  3654     }
  3655 }
  3656 
  3657 int
  3658 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3659 {
  3660     int dummybutton;
  3661     int retval = -1;
  3662     SDL_bool relative_mode;
  3663     int show_cursor_prev;
  3664     SDL_bool mouse_captured;
  3665     SDL_Window *current_window;
  3666 
  3667     if (!messageboxdata) {
  3668         return SDL_InvalidParamError("messageboxdata");
  3669     }
  3670 
  3671     current_window = SDL_GetKeyboardFocus();
  3672     mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
  3673     relative_mode = SDL_GetRelativeMouseMode();
  3674     SDL_CaptureMouse(SDL_FALSE);
  3675     SDL_SetRelativeMouseMode(SDL_FALSE);
  3676     show_cursor_prev = SDL_ShowCursor(1);
  3677     SDL_ResetKeyboard();
  3678 
  3679     if (!buttonid) {
  3680         buttonid = &dummybutton;
  3681     }
  3682 
  3683     if (_this && _this->ShowMessageBox) {
  3684         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3685     }
  3686 
  3687     /* It's completely fine to call this function before video is initialized */
  3688 #if SDL_VIDEO_DRIVER_ANDROID
  3689     if (retval == -1 &&
  3690         Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3691         retval = 0;
  3692     }
  3693 #endif
  3694 #if SDL_VIDEO_DRIVER_WINDOWS
  3695     if (retval == -1 &&
  3696         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3697         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3698         retval = 0;
  3699     }
  3700 #endif
  3701 #if SDL_VIDEO_DRIVER_WINRT
  3702     if (retval == -1 &&
  3703         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
  3704         WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3705         retval = 0;
  3706     }
  3707 #endif
  3708 #if SDL_VIDEO_DRIVER_COCOA
  3709     if (retval == -1 &&
  3710         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3711         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3712         retval = 0;
  3713     }
  3714 #endif
  3715 #if SDL_VIDEO_DRIVER_UIKIT
  3716     if (retval == -1 &&
  3717         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3718         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3719         retval = 0;
  3720     }
  3721 #endif
  3722 #if SDL_VIDEO_DRIVER_X11
  3723     if (retval == -1 &&
  3724         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3725         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3726         retval = 0;
  3727     }
  3728 #endif
  3729     if (retval == -1) {
  3730         SDL_SetError("No message system available");
  3731     }
  3732 
  3733     if (current_window) {
  3734         SDL_RaiseWindow(current_window);
  3735         if (mouse_captured) {
  3736             SDL_CaptureMouse(SDL_TRUE);
  3737         }
  3738     }
  3739 
  3740     SDL_ShowCursor(show_cursor_prev);
  3741     SDL_SetRelativeMouseMode(relative_mode);
  3742 
  3743     return retval;
  3744 }
  3745 
  3746 int
  3747 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3748 {
  3749 #ifdef __EMSCRIPTEN__
  3750     /* !!! FIXME: propose a browser API for this, get this #ifdef out of here? */
  3751     /* Web browsers don't (currently) have an API for a custom message box
  3752        that can block, but for the most common case (SDL_ShowSimpleMessageBox),
  3753        we can use the standard Javascript alert() function. */
  3754     EM_ASM_({
  3755         alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1));
  3756     }, title, message);
  3757     return 0;
  3758 #else
  3759     SDL_MessageBoxData data;
  3760     SDL_MessageBoxButtonData button;
  3761 
  3762     SDL_zero(data);
  3763     data.flags = flags;
  3764     data.title = title;
  3765     data.message = message;
  3766     data.numbuttons = 1;
  3767     data.buttons = &button;
  3768     data.window = window;
  3769 
  3770     SDL_zero(button);
  3771     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3772     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3773     button.text = "OK";
  3774 
  3775     return SDL_ShowMessageBox(&data, NULL);
  3776 #endif
  3777 }
  3778 
  3779 SDL_bool
  3780 SDL_ShouldAllowTopmost(void)
  3781 {
  3782     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3783     if (hint) {
  3784         if (*hint == '0') {
  3785             return SDL_FALSE;
  3786         } else {
  3787             return SDL_TRUE;
  3788         }
  3789     }
  3790     return SDL_TRUE;
  3791 }
  3792 
  3793 int
  3794 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
  3795 {
  3796     CHECK_WINDOW_MAGIC(window, -1);
  3797 
  3798     if (!_this->SetWindowHitTest) {
  3799         return SDL_Unsupported();
  3800     } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
  3801         return -1;
  3802     }
  3803 
  3804     window->hit_test = callback;
  3805     window->hit_test_data = userdata;
  3806 
  3807     return 0;
  3808 }
  3809 
  3810 float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
  3811 {
  3812 	float den2 = hinches * hinches + vinches * vinches;
  3813 	if ( den2 <= 0.0f ) {
  3814 		return 0.0f;
  3815 	}
  3816 		
  3817 	return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
  3818 				   SDL_sqrt((double)den2));
  3819 }
  3820 
  3821 /* vi: set ts=4 sw=4 expandtab: */