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