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