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