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