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