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