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