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