src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 30 Sep 2012 01:08:48 -0700
changeset 6522 edacce9402fb
parent 6518 42948831d16e
child 6547 38bc368a3b87
permissions -rw-r--r--
The gl_data is optional for the driver, so don't early out of the context delete call if it doesn't exist.
     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     /* We're ready to go! */
   526     return 0;
   527 }
   528 
   529 const char *
   530 SDL_GetCurrentVideoDriver()
   531 {
   532     if (!_this) {
   533         SDL_UninitializedVideo();
   534         return NULL;
   535     }
   536     return _this->name;
   537 }
   538 
   539 SDL_VideoDevice *
   540 SDL_GetVideoDevice(void)
   541 {
   542     return _this;
   543 }
   544 
   545 int
   546 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   547 {
   548     SDL_VideoDisplay display;
   549 
   550     SDL_zero(display);
   551     if (desktop_mode) {
   552         display.desktop_mode = *desktop_mode;
   553     }
   554     display.current_mode = display.desktop_mode;
   555 
   556     return SDL_AddVideoDisplay(&display);
   557 }
   558 
   559 int
   560 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   561 {
   562     SDL_VideoDisplay *displays;
   563     int index = -1;
   564 
   565     displays =
   566         SDL_realloc(_this->displays,
   567                     (_this->num_displays + 1) * sizeof(*displays));
   568     if (displays) {
   569         index = _this->num_displays++;
   570         displays[index] = *display;
   571         displays[index].device = _this;
   572         _this->displays = displays;
   573     } else {
   574         SDL_OutOfMemory();
   575     }
   576     return index;
   577 }
   578 
   579 int
   580 SDL_GetNumVideoDisplays(void)
   581 {
   582     if (!_this) {
   583         SDL_UninitializedVideo();
   584         return 0;
   585     }
   586     return _this->num_displays;
   587 }
   588 
   589 static int
   590 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   591 {
   592     int displayIndex;
   593 
   594     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   595         if (display == &_this->displays[displayIndex]) {
   596             return displayIndex;
   597         }
   598     }
   599 
   600     /* Couldn't find the display, just use index 0 */
   601     return 0;
   602 }
   603 
   604 int
   605 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   606 {
   607     CHECK_DISPLAY_INDEX(displayIndex, -1);
   608 
   609     if (rect) {
   610         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   611 
   612         if (_this->GetDisplayBounds) {
   613             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   614                 return 0;
   615             }
   616         }
   617 
   618         /* Assume that the displays are left to right */
   619         if (displayIndex == 0) {
   620             rect->x = 0;
   621             rect->y = 0;
   622         } else {
   623             SDL_GetDisplayBounds(displayIndex-1, rect);
   624             rect->x += rect->w;
   625         }
   626         rect->w = display->current_mode.w;
   627         rect->h = display->current_mode.h;
   628     }
   629     return 0;
   630 }
   631 
   632 SDL_bool
   633 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   634 {
   635     SDL_DisplayMode *modes;
   636     int i, nmodes;
   637 
   638     /* Make sure we don't already have the mode in the list */
   639     modes = display->display_modes;
   640     nmodes = display->num_display_modes;
   641     for (i = nmodes; i--;) {
   642         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   643             return SDL_FALSE;
   644         }
   645     }
   646 
   647     /* Go ahead and add the new mode */
   648     if (nmodes == display->max_display_modes) {
   649         modes =
   650             SDL_realloc(modes,
   651                         (display->max_display_modes + 32) * sizeof(*modes));
   652         if (!modes) {
   653             return SDL_FALSE;
   654         }
   655         display->display_modes = modes;
   656         display->max_display_modes += 32;
   657     }
   658     modes[nmodes] = *mode;
   659     display->num_display_modes++;
   660 
   661     /* Re-sort video modes */
   662     SDL_qsort(display->display_modes, display->num_display_modes,
   663               sizeof(SDL_DisplayMode), cmpmodes);
   664 
   665     return SDL_TRUE;
   666 }
   667 
   668 static int
   669 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   670 {
   671     if (!display->num_display_modes && _this->GetDisplayModes) {
   672         _this->GetDisplayModes(_this, display);
   673         SDL_qsort(display->display_modes, display->num_display_modes,
   674                   sizeof(SDL_DisplayMode), cmpmodes);
   675     }
   676     return display->num_display_modes;
   677 }
   678 
   679 int
   680 SDL_GetNumDisplayModes(int displayIndex)
   681 {
   682     CHECK_DISPLAY_INDEX(displayIndex, -1);
   683 
   684     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   685 }
   686 
   687 int
   688 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   689 {
   690     SDL_VideoDisplay *display;
   691 
   692     CHECK_DISPLAY_INDEX(displayIndex, -1);
   693 
   694     display = &_this->displays[displayIndex];
   695     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   696         SDL_SetError("index must be in the range of 0 - %d",
   697                      SDL_GetNumDisplayModesForDisplay(display) - 1);
   698         return -1;
   699     }
   700     if (mode) {
   701         *mode = display->display_modes[index];
   702     }
   703     return 0;
   704 }
   705 
   706 int
   707 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   708 {
   709     SDL_VideoDisplay *display;
   710 
   711     CHECK_DISPLAY_INDEX(displayIndex, -1);
   712 
   713     display = &_this->displays[displayIndex];
   714     if (mode) {
   715         *mode = display->desktop_mode;
   716     }
   717     return 0;
   718 }
   719 
   720 int
   721 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   722 {
   723     SDL_VideoDisplay *display;
   724 
   725     CHECK_DISPLAY_INDEX(displayIndex, -1);
   726 
   727     display = &_this->displays[displayIndex];
   728     if (mode) {
   729         *mode = display->current_mode;
   730     }
   731     return 0;
   732 }
   733 
   734 static SDL_DisplayMode *
   735 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   736                                     const SDL_DisplayMode * mode,
   737                                     SDL_DisplayMode * closest)
   738 {
   739     Uint32 target_format;
   740     int target_refresh_rate;
   741     int i;
   742     SDL_DisplayMode *current, *match;
   743 
   744     if (!mode || !closest) {
   745         SDL_SetError("Missing desired mode or closest mode parameter");
   746         return NULL;
   747     }
   748 
   749     /* Default to the desktop format */
   750     if (mode->format) {
   751         target_format = mode->format;
   752     } else {
   753         target_format = display->desktop_mode.format;
   754     }
   755 
   756     /* Default to the desktop refresh rate */
   757     if (mode->refresh_rate) {
   758         target_refresh_rate = mode->refresh_rate;
   759     } else {
   760         target_refresh_rate = display->desktop_mode.refresh_rate;
   761     }
   762 
   763     match = NULL;
   764     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   765         current = &display->display_modes[i];
   766 
   767         if (current->w && (current->w < mode->w)) {
   768             /* Out of sorted modes large enough here */
   769             break;
   770         }
   771         if (current->h && (current->h < mode->h)) {
   772             if (current->w && (current->w == mode->w)) {
   773                 /* Out of sorted modes large enough here */
   774                 break;
   775             }
   776             /* Wider, but not tall enough, due to a different
   777                aspect ratio. This mode must be skipped, but closer
   778                modes may still follow. */
   779             continue;
   780         }
   781         if (!match || current->w < match->w || current->h < match->h) {
   782             match = current;
   783             continue;
   784         }
   785         if (current->format != match->format) {
   786             /* Sorted highest depth to lowest */
   787             if (current->format == target_format ||
   788                 (SDL_BITSPERPIXEL(current->format) >=
   789                  SDL_BITSPERPIXEL(target_format)
   790                  && SDL_PIXELTYPE(current->format) ==
   791                  SDL_PIXELTYPE(target_format))) {
   792                 match = current;
   793             }
   794             continue;
   795         }
   796         if (current->refresh_rate != match->refresh_rate) {
   797             /* Sorted highest refresh to lowest */
   798             if (current->refresh_rate >= target_refresh_rate) {
   799                 match = current;
   800             }
   801         }
   802     }
   803     if (match) {
   804         if (match->format) {
   805             closest->format = match->format;
   806         } else {
   807             closest->format = mode->format;
   808         }
   809         if (match->w && match->h) {
   810             closest->w = match->w;
   811             closest->h = match->h;
   812         } else {
   813             closest->w = mode->w;
   814             closest->h = mode->h;
   815         }
   816         if (match->refresh_rate) {
   817             closest->refresh_rate = match->refresh_rate;
   818         } else {
   819             closest->refresh_rate = mode->refresh_rate;
   820         }
   821         closest->driverdata = match->driverdata;
   822 
   823         /*
   824          * Pick some reasonable defaults if the app and driver don't
   825          * care
   826          */
   827         if (!closest->format) {
   828             closest->format = SDL_PIXELFORMAT_RGB888;
   829         }
   830         if (!closest->w) {
   831             closest->w = 640;
   832         }
   833         if (!closest->h) {
   834             closest->h = 480;
   835         }
   836         return closest;
   837     }
   838     return NULL;
   839 }
   840 
   841 SDL_DisplayMode *
   842 SDL_GetClosestDisplayMode(int displayIndex,
   843                           const SDL_DisplayMode * mode,
   844                           SDL_DisplayMode * closest)
   845 {
   846     SDL_VideoDisplay *display;
   847 
   848     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   849 
   850     display = &_this->displays[displayIndex];
   851     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   852 }
   853 
   854 static int
   855 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   856 {
   857     SDL_DisplayMode display_mode;
   858     SDL_DisplayMode current_mode;
   859 
   860     if (mode) {
   861         display_mode = *mode;
   862 
   863         /* Default to the current mode */
   864         if (!display_mode.format) {
   865             display_mode.format = display->current_mode.format;
   866         }
   867         if (!display_mode.w) {
   868             display_mode.w = display->current_mode.w;
   869         }
   870         if (!display_mode.h) {
   871             display_mode.h = display->current_mode.h;
   872         }
   873         if (!display_mode.refresh_rate) {
   874             display_mode.refresh_rate = display->current_mode.refresh_rate;
   875         }
   876 
   877         /* Get a good video mode, the closest one possible */
   878         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   879             SDL_SetError("No video mode large enough for %dx%d",
   880                          display_mode.w, display_mode.h);
   881             return -1;
   882         }
   883     } else {
   884         display_mode = display->desktop_mode;
   885     }
   886 
   887     /* See if there's anything left to do */
   888     current_mode = display->current_mode;
   889     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   890         return 0;
   891     }
   892 
   893     /* Actually change the display mode */
   894     if (!_this->SetDisplayMode) {
   895         SDL_SetError("Video driver doesn't support changing display mode");
   896         return -1;
   897     }
   898     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   899         return -1;
   900     }
   901     display->current_mode = display_mode;
   902     return 0;
   903 }
   904 
   905 int
   906 SDL_GetWindowDisplay(SDL_Window * window)
   907 {
   908     int displayIndex;
   909     int i, dist;
   910     int closest = -1;
   911     int closest_dist = 0x7FFFFFFF;
   912     SDL_Point center;
   913     SDL_Point delta;
   914     SDL_Rect rect;
   915 
   916     CHECK_WINDOW_MAGIC(window, -1);
   917 
   918     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   919         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   920         displayIndex = (window->x & 0xFFFF);
   921         if (displayIndex >= _this->num_displays) {
   922             displayIndex = 0;
   923         }
   924         return displayIndex;
   925     }
   926     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   927         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   928         displayIndex = (window->y & 0xFFFF);
   929         if (displayIndex >= _this->num_displays) {
   930             displayIndex = 0;
   931         }
   932         return displayIndex;
   933     }
   934 
   935     /* Find the display containing the window */
   936     center.x = window->x + window->w / 2;
   937     center.y = window->y + window->h / 2;
   938     for (i = 0; i < _this->num_displays; ++i) {
   939         SDL_VideoDisplay *display = &_this->displays[i];
   940 
   941         SDL_GetDisplayBounds(i, &rect);
   942         if (display->fullscreen_window == window || SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   943             return i;
   944         }
   945 
   946         delta.x = center.x - (rect.x + rect.w / 2);
   947         delta.y = center.y - (rect.y + rect.h / 2);
   948         dist = (delta.x*delta.x + delta.y*delta.y);
   949         if (dist < closest_dist) {
   950             closest = i;
   951             closest_dist = dist;
   952         }
   953     }
   954     if (closest < 0) {
   955         SDL_SetError("Couldn't find any displays");
   956     }
   957     return closest;
   958 }
   959 
   960 SDL_VideoDisplay *
   961 SDL_GetDisplayForWindow(SDL_Window *window)
   962 {
   963     int displayIndex = SDL_GetWindowDisplay(window);
   964     if (displayIndex >= 0) {
   965         return &_this->displays[displayIndex];
   966     } else {
   967         return NULL;
   968     }
   969 }
   970 
   971 int
   972 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   973 {
   974     CHECK_WINDOW_MAGIC(window, -1);
   975 
   976     if (mode) {
   977         window->fullscreen_mode = *mode;
   978     } else {
   979         SDL_zero(window->fullscreen_mode);
   980     }
   981     return 0;
   982 }
   983 
   984 int
   985 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
   986 {
   987     SDL_DisplayMode fullscreen_mode;
   988 
   989     CHECK_WINDOW_MAGIC(window, -1);
   990 
   991     fullscreen_mode = window->fullscreen_mode;
   992     if (!fullscreen_mode.w) {
   993         fullscreen_mode.w = window->w;
   994     }
   995     if (!fullscreen_mode.h) {
   996         fullscreen_mode.h = window->h;
   997     }
   998 
   999     if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
  1000                                              &fullscreen_mode,
  1001                                              &fullscreen_mode)) {
  1002         SDL_SetError("Couldn't find display mode match");
  1003         return -1;
  1004     }
  1005 
  1006     if (mode) {
  1007         *mode = fullscreen_mode;
  1008     }
  1009     return 0;
  1010 }
  1011 
  1012 Uint32
  1013 SDL_GetWindowPixelFormat(SDL_Window * window)
  1014 {
  1015     SDL_VideoDisplay *display;
  1016 
  1017     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1018 
  1019     display = SDL_GetDisplayForWindow(window);
  1020     return display->current_mode.format;
  1021 }
  1022 
  1023 static void
  1024 SDL_RestoreMousePosition(SDL_Window *window)
  1025 {
  1026     int x, y;
  1027 
  1028     if (window == SDL_GetMouseFocus()) {
  1029         SDL_GetMouseState(&x, &y);
  1030         SDL_WarpMouseInWindow(window, x, y);
  1031     }
  1032 }
  1033 
  1034 static void
  1035 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1036 {
  1037     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1038     SDL_Window *other;
  1039 
  1040     if (fullscreen) {
  1041         /* Hide any other fullscreen windows */
  1042         if (display->fullscreen_window &&
  1043             display->fullscreen_window != window) {
  1044             SDL_MinimizeWindow(display->fullscreen_window);
  1045         }
  1046     }
  1047 
  1048     /* See if anything needs to be done now */
  1049     if ((display->fullscreen_window == window) == fullscreen) {
  1050         return;
  1051     }
  1052 
  1053     /* See if there are any fullscreen windows */
  1054     for (other = _this->windows; other; other = other->next) {
  1055         SDL_bool setDisplayMode = SDL_FALSE;
  1056 
  1057         if (other == window) {
  1058             setDisplayMode = fullscreen;
  1059         } else if (FULLSCREEN_VISIBLE(other) &&
  1060                    SDL_GetDisplayForWindow(other) == display) {
  1061             setDisplayMode = SDL_TRUE;
  1062         }
  1063 
  1064         if (setDisplayMode) {
  1065             SDL_DisplayMode fullscreen_mode;
  1066 
  1067             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1068                 SDL_bool resized = SDL_TRUE;
  1069 
  1070                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1071                     resized = SDL_FALSE;
  1072                 }
  1073 
  1074                 SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1075                 if (_this->SetWindowFullscreen) {
  1076                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1077                 }
  1078                 display->fullscreen_window = other;
  1079 
  1080                 /* Generate a mode change event here */
  1081                 if (resized) {
  1082                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1083                                         fullscreen_mode.w, fullscreen_mode.h);
  1084                 } else {
  1085                     SDL_OnWindowResized(other);
  1086                 }
  1087 
  1088                 SDL_RestoreMousePosition(other);
  1089                 return;
  1090             }
  1091         }
  1092     }
  1093 
  1094     /* Nope, restore the desktop mode */
  1095     SDL_SetDisplayModeForDisplay(display, NULL);
  1096 
  1097     if (_this->SetWindowFullscreen) {
  1098         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1099     }
  1100     display->fullscreen_window = NULL;
  1101 
  1102     /* Generate a mode change event here */
  1103     SDL_OnWindowResized(window);
  1104 
  1105     /* Restore the cursor position */
  1106     SDL_RestoreMousePosition(window);
  1107 }
  1108 
  1109 #define CREATE_FLAGS \
  1110     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE)
  1111 
  1112 static void
  1113 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1114 {
  1115     window->windowed.x = window->x;
  1116     window->windowed.y = window->y;
  1117     window->windowed.w = window->w;
  1118     window->windowed.h = window->h;
  1119 
  1120     if (flags & SDL_WINDOW_MAXIMIZED) {
  1121         SDL_MaximizeWindow(window);
  1122     }
  1123     if (flags & SDL_WINDOW_MINIMIZED) {
  1124         SDL_MinimizeWindow(window);
  1125     }
  1126     if (flags & SDL_WINDOW_FULLSCREEN) {
  1127         SDL_SetWindowFullscreen(window, SDL_TRUE);
  1128     }
  1129     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1130         SDL_SetWindowGrab(window, SDL_TRUE);
  1131     }
  1132     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1133         SDL_ShowWindow(window);
  1134     }
  1135 }
  1136 
  1137 SDL_Window *
  1138 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1139 {
  1140     SDL_Window *window;
  1141 
  1142     if (!_this) {
  1143         /* Initialize the video system if needed */
  1144         if (SDL_VideoInit(NULL) < 0) {
  1145             return NULL;
  1146         }
  1147     }
  1148 
  1149     /* Some platforms can't create zero-sized windows */
  1150     if (w < 1) {
  1151         w = 1;
  1152     }
  1153     if (h < 1) {
  1154         h = 1;
  1155     }
  1156 
  1157     /* Some platforms have OpenGL enabled by default */
  1158 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__
  1159     flags |= SDL_WINDOW_OPENGL;
  1160 #endif
  1161     if (flags & SDL_WINDOW_OPENGL) {
  1162         if (!_this->GL_CreateContext) {
  1163             SDL_SetError("No OpenGL support in video driver");
  1164             return NULL;
  1165         }
  1166         SDL_GL_LoadLibrary(NULL);
  1167     }
  1168     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1169     window->magic = &_this->window_magic;
  1170     window->id = _this->next_object_id++;
  1171     window->x = x;
  1172     window->y = y;
  1173     window->w = w;
  1174     window->h = h;
  1175     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1176         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1177         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1178         int displayIndex;
  1179         SDL_Rect bounds;
  1180 
  1181         displayIndex = SDL_GetIndexOfDisplay(display);
  1182         SDL_GetDisplayBounds(displayIndex, &bounds);
  1183         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1184             window->x = bounds.x + (bounds.w - w) / 2;
  1185         }
  1186         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1187             window->y = bounds.y + (bounds.h - h) / 2;
  1188         }
  1189     }
  1190     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1191     window->brightness = 1.0f;
  1192     window->next = _this->windows;
  1193     if (_this->windows) {
  1194         _this->windows->prev = window;
  1195     }
  1196     _this->windows = window;
  1197 
  1198     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1199         SDL_DestroyWindow(window);
  1200         return NULL;
  1201     }
  1202 
  1203     if (title) {
  1204         SDL_SetWindowTitle(window, title);
  1205     }
  1206     SDL_FinishWindowCreation(window, flags);
  1207     
  1208     /* If the window was created fullscreen, make sure the mode code matches */
  1209     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1210 
  1211     return window;
  1212 }
  1213 
  1214 SDL_Window *
  1215 SDL_CreateWindowFrom(const void *data)
  1216 {
  1217     SDL_Window *window;
  1218 
  1219     if (!_this) {
  1220         SDL_UninitializedVideo();
  1221         return NULL;
  1222     }
  1223     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1224     window->magic = &_this->window_magic;
  1225     window->id = _this->next_object_id++;
  1226     window->flags = SDL_WINDOW_FOREIGN;
  1227     window->brightness = 1.0f;
  1228     window->next = _this->windows;
  1229     if (_this->windows) {
  1230         _this->windows->prev = window;
  1231     }
  1232     _this->windows = window;
  1233 
  1234     if (!_this->CreateWindowFrom ||
  1235         _this->CreateWindowFrom(_this, window, data) < 0) {
  1236         SDL_DestroyWindow(window);
  1237         return NULL;
  1238     }
  1239     return window;
  1240 }
  1241 
  1242 int
  1243 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1244 {
  1245     char *title = window->title;
  1246 
  1247     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1248         SDL_SetError("No OpenGL support in video driver");
  1249         return -1;
  1250     }
  1251 
  1252     if (window->flags & SDL_WINDOW_FOREIGN) {
  1253         /* Can't destroy and re-create foreign windows, hrm */
  1254         flags |= SDL_WINDOW_FOREIGN;
  1255     } else {
  1256         flags &= ~SDL_WINDOW_FOREIGN;
  1257     }
  1258 
  1259     /* Restore video mode, etc. */
  1260     SDL_HideWindow(window);
  1261 
  1262     /* Tear down the old native window */
  1263     if (window->surface) {
  1264         window->surface->flags &= ~SDL_DONTFREE;
  1265         SDL_FreeSurface(window->surface);
  1266     }
  1267     if (_this->DestroyWindowFramebuffer) {
  1268         _this->DestroyWindowFramebuffer(_this, window);
  1269     }
  1270     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1271         _this->DestroyWindow(_this, window);
  1272     }
  1273 
  1274     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1275         if (flags & SDL_WINDOW_OPENGL) {
  1276             SDL_GL_LoadLibrary(NULL);
  1277         } else {
  1278             SDL_GL_UnloadLibrary();
  1279         }
  1280     }
  1281 
  1282     window->title = NULL;
  1283     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1284 
  1285     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1286         if (_this->CreateWindow(_this, window) < 0) {
  1287             if (flags & SDL_WINDOW_OPENGL) {
  1288                 SDL_GL_UnloadLibrary();
  1289             }
  1290             return -1;
  1291         }
  1292     }
  1293 
  1294     if (title) {
  1295         SDL_SetWindowTitle(window, title);
  1296         SDL_free(title);
  1297     }
  1298     SDL_FinishWindowCreation(window, flags);
  1299 
  1300     return 0;
  1301 }
  1302 
  1303 Uint32
  1304 SDL_GetWindowID(SDL_Window * window)
  1305 {
  1306     CHECK_WINDOW_MAGIC(window, 0);
  1307 
  1308     return window->id;
  1309 }
  1310 
  1311 SDL_Window *
  1312 SDL_GetWindowFromID(Uint32 id)
  1313 {
  1314     SDL_Window *window;
  1315 
  1316     if (!_this) {
  1317         return NULL;
  1318     }
  1319     for (window = _this->windows; window; window = window->next) {
  1320         if (window->id == id) {
  1321             return window;
  1322         }
  1323     }
  1324     return NULL;
  1325 }
  1326 
  1327 Uint32
  1328 SDL_GetWindowFlags(SDL_Window * window)
  1329 {
  1330     CHECK_WINDOW_MAGIC(window, 0);
  1331 
  1332     return window->flags;
  1333 }
  1334 
  1335 void
  1336 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1337 {
  1338     CHECK_WINDOW_MAGIC(window, );
  1339 
  1340     if (title == window->title) {
  1341         return;
  1342     }
  1343     if (window->title) {
  1344         SDL_free(window->title);
  1345     }
  1346     if (title && *title) {
  1347         window->title = SDL_strdup(title);
  1348     } else {
  1349         window->title = NULL;
  1350     }
  1351 
  1352     if (_this->SetWindowTitle) {
  1353         _this->SetWindowTitle(_this, window);
  1354     }
  1355 }
  1356 
  1357 const char *
  1358 SDL_GetWindowTitle(SDL_Window * window)
  1359 {
  1360     CHECK_WINDOW_MAGIC(window, "");
  1361 
  1362     return window->title ? window->title : "";
  1363 }
  1364 
  1365 void
  1366 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1367 {
  1368     CHECK_WINDOW_MAGIC(window, );
  1369 
  1370     if (!icon) {
  1371         return;
  1372     }
  1373 
  1374     if (_this->SetWindowIcon) {
  1375         _this->SetWindowIcon(_this, window, icon);
  1376     }
  1377 }
  1378 
  1379 void*
  1380 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1381 {
  1382     SDL_WindowUserData *prev, *data;
  1383 
  1384     CHECK_WINDOW_MAGIC(window, NULL);
  1385 
  1386     /* See if the named data already exists */
  1387     prev = NULL;
  1388     for (data = window->data; data; prev = data, data = data->next) {
  1389         if (SDL_strcmp(data->name, name) == 0) {
  1390             void *last_value = data->data;
  1391 
  1392             if (userdata) {
  1393                 /* Set the new value */
  1394                 data->data = userdata;
  1395             } else {
  1396                 /* Delete this value */
  1397                 if (prev) {
  1398                     prev->next = data->next;
  1399                 } else {
  1400                     window->data = data->next;
  1401                 }
  1402                 SDL_free(data->name);
  1403                 SDL_free(data);
  1404             }
  1405             return last_value;
  1406         }
  1407     }
  1408 
  1409     /* Add new data to the window */
  1410     if (userdata) {
  1411         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1412         data->name = SDL_strdup(name);
  1413         data->data = userdata;
  1414         data->next = window->data;
  1415         window->data = data;
  1416     }
  1417     return NULL;
  1418 }
  1419 
  1420 void *
  1421 SDL_GetWindowData(SDL_Window * window, const char *name)
  1422 {
  1423     SDL_WindowUserData *data;
  1424 
  1425     CHECK_WINDOW_MAGIC(window, NULL);
  1426 
  1427     for (data = window->data; data; data = data->next) {
  1428         if (SDL_strcmp(data->name, name) == 0) {
  1429             return data->data;
  1430         }
  1431     }
  1432     return NULL;
  1433 }
  1434 
  1435 void
  1436 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1437 {
  1438     CHECK_WINDOW_MAGIC(window, );
  1439 
  1440     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1441         window->x = x;
  1442     }
  1443     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1444         window->y = y;
  1445     }
  1446     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1447         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1448         int displayIndex;
  1449         SDL_Rect bounds;
  1450 
  1451         displayIndex = SDL_GetIndexOfDisplay(display);
  1452         SDL_GetDisplayBounds(displayIndex, &bounds);
  1453         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1454             window->x = bounds.x + (bounds.w - window->w) / 2;
  1455         }
  1456         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1457             window->y = bounds.y + (bounds.h - window->h) / 2;
  1458         }
  1459     }
  1460     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1461         if (_this->SetWindowPosition) {
  1462             _this->SetWindowPosition(_this, window);
  1463         }
  1464         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1465     }
  1466 }
  1467 
  1468 void
  1469 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1470 {
  1471     /* Clear the values */
  1472     if (x) {
  1473         *x = 0;
  1474     }
  1475     if (y) {
  1476         *y = 0;
  1477     }
  1478 
  1479     CHECK_WINDOW_MAGIC(window, );
  1480 
  1481     /* Fullscreen windows are always at their display's origin */
  1482     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1483     } else {
  1484         if (x) {
  1485             *x = window->x;
  1486         }
  1487         if (y) {
  1488             *y = window->y;
  1489         }
  1490     }
  1491 }
  1492 
  1493 void
  1494 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1495 {
  1496     CHECK_WINDOW_MAGIC(window, );
  1497     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1498         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1499         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1500         if ((want != have) && (_this->SetWindowBordered)) {
  1501             if (want) {
  1502                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1503             } else {
  1504                 window->flags |= SDL_WINDOW_BORDERLESS;
  1505             }
  1506             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1507         }
  1508     }
  1509 }
  1510 
  1511 void
  1512 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1513 {
  1514     CHECK_WINDOW_MAGIC(window, );
  1515 
  1516     /* FIXME: Should this change fullscreen modes? */
  1517     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1518         window->w = w;
  1519         window->h = h;
  1520         if (_this->SetWindowSize) {
  1521             _this->SetWindowSize(_this, window);
  1522         }
  1523         if (window->w == w && window->h == h) {
  1524             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1525             SDL_OnWindowResized(window);
  1526         }
  1527     }
  1528 }
  1529 
  1530 void
  1531 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1532 {
  1533     int dummy;
  1534 
  1535     if (!w) {
  1536         w = &dummy;
  1537     }
  1538     if (!h) {
  1539         h = &dummy;
  1540     }
  1541 
  1542     *w = 0;
  1543     *h = 0;
  1544 
  1545     CHECK_WINDOW_MAGIC(window, );
  1546 
  1547     if (_this && window && window->magic == &_this->window_magic) {
  1548         if (w) {
  1549             *w = window->w;
  1550         }
  1551         if (h) {
  1552             *h = window->h;
  1553         }
  1554     } else {
  1555         if (w) {
  1556             *w = 0;
  1557         }
  1558         if (h) {
  1559             *h = 0;
  1560         }
  1561     }
  1562 }
  1563 
  1564 void
  1565 SDL_ShowWindow(SDL_Window * window)
  1566 {
  1567     CHECK_WINDOW_MAGIC(window, );
  1568 
  1569     if (window->flags & SDL_WINDOW_SHOWN) {
  1570         return;
  1571     }
  1572 
  1573     if (_this->ShowWindow) {
  1574         _this->ShowWindow(_this, window);
  1575     }
  1576     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1577 }
  1578 
  1579 void
  1580 SDL_HideWindow(SDL_Window * window)
  1581 {
  1582     CHECK_WINDOW_MAGIC(window, );
  1583 
  1584     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1585         return;
  1586     }
  1587 
  1588     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1589 
  1590     if (_this->HideWindow) {
  1591         _this->HideWindow(_this, window);
  1592     }
  1593     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1594 }
  1595 
  1596 void
  1597 SDL_RaiseWindow(SDL_Window * window)
  1598 {
  1599     CHECK_WINDOW_MAGIC(window, );
  1600 
  1601     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1602         return;
  1603     }
  1604     if (_this->RaiseWindow) {
  1605         _this->RaiseWindow(_this, window);
  1606     }
  1607 }
  1608 
  1609 void
  1610 SDL_MaximizeWindow(SDL_Window * window)
  1611 {
  1612     CHECK_WINDOW_MAGIC(window, );
  1613 
  1614     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1615         return;
  1616     }
  1617 
  1618     if (_this->MaximizeWindow) {
  1619         _this->MaximizeWindow(_this, window);
  1620     }
  1621 }
  1622 
  1623 void
  1624 SDL_MinimizeWindow(SDL_Window * window)
  1625 {
  1626     CHECK_WINDOW_MAGIC(window, );
  1627 
  1628     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1629         return;
  1630     }
  1631 
  1632     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1633 
  1634     if (_this->MinimizeWindow) {
  1635         _this->MinimizeWindow(_this, window);
  1636     }
  1637 }
  1638 
  1639 void
  1640 SDL_RestoreWindow(SDL_Window * window)
  1641 {
  1642     CHECK_WINDOW_MAGIC(window, );
  1643 
  1644     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1645         return;
  1646     }
  1647 
  1648     if (_this->RestoreWindow) {
  1649         _this->RestoreWindow(_this, window);
  1650     }
  1651 }
  1652 
  1653 int
  1654 SDL_SetWindowFullscreen(SDL_Window * window, SDL_bool fullscreen)
  1655 {
  1656     CHECK_WINDOW_MAGIC(window, -1);
  1657 
  1658     if (!!fullscreen == !!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1659         return 0;
  1660     }
  1661     if (fullscreen) {
  1662         window->flags |= SDL_WINDOW_FULLSCREEN;
  1663     } else {
  1664         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1665     }
  1666     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1667 
  1668     return 0;
  1669 }
  1670 
  1671 static SDL_Surface *
  1672 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1673 {
  1674     Uint32 format;
  1675     void *pixels;
  1676     int pitch;
  1677     int bpp;
  1678     Uint32 Rmask, Gmask, Bmask, Amask;
  1679 
  1680     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1681         return NULL;
  1682     }
  1683 
  1684     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1685         return NULL;
  1686     }
  1687 
  1688     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1689         return NULL;
  1690     }
  1691 
  1692     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1693 }
  1694 
  1695 SDL_Surface *
  1696 SDL_GetWindowSurface(SDL_Window * window)
  1697 {
  1698     CHECK_WINDOW_MAGIC(window, NULL);
  1699 
  1700     if (!window->surface_valid) {
  1701         if (window->surface) {
  1702             window->surface->flags &= ~SDL_DONTFREE;
  1703             SDL_FreeSurface(window->surface);
  1704         }
  1705         window->surface = SDL_CreateWindowFramebuffer(window);
  1706         if (window->surface) {
  1707             window->surface_valid = SDL_TRUE;
  1708             window->surface->flags |= SDL_DONTFREE;
  1709         }
  1710     }
  1711     return window->surface;
  1712 }
  1713 
  1714 int
  1715 SDL_UpdateWindowSurface(SDL_Window * window)
  1716 {
  1717     SDL_Rect full_rect;
  1718 
  1719     CHECK_WINDOW_MAGIC(window, -1);
  1720 
  1721     full_rect.x = 0;
  1722     full_rect.y = 0;
  1723     full_rect.w = window->w;
  1724     full_rect.h = window->h;
  1725     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1726 }
  1727 
  1728 int
  1729 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
  1730                              int numrects)
  1731 {
  1732     CHECK_WINDOW_MAGIC(window, -1);
  1733 
  1734     if (!window->surface_valid) {
  1735         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1736         return -1;
  1737     }
  1738 
  1739     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1740 }
  1741 
  1742 int
  1743 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1744 {
  1745     Uint16 ramp[256];
  1746     int status;
  1747 
  1748     CHECK_WINDOW_MAGIC(window, -1);
  1749 
  1750     SDL_CalculateGammaRamp(brightness, ramp);
  1751     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1752     if (status == 0) {
  1753         window->brightness = brightness;
  1754     }
  1755     return status;
  1756 }
  1757 
  1758 float
  1759 SDL_GetWindowBrightness(SDL_Window * window)
  1760 {
  1761     CHECK_WINDOW_MAGIC(window, 1.0f);
  1762 
  1763     return window->brightness;
  1764 }
  1765 
  1766 int
  1767 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1768                                             const Uint16 * green,
  1769                                             const Uint16 * blue)
  1770 {
  1771     CHECK_WINDOW_MAGIC(window, -1);
  1772 
  1773     if (!_this->SetWindowGammaRamp) {
  1774         SDL_Unsupported();
  1775         return -1;
  1776     }
  1777 
  1778     if (!window->gamma) {
  1779         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1780             return -1;
  1781         }
  1782     }
  1783 
  1784     if (red) {
  1785         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1786     }
  1787     if (green) {
  1788         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1789     }
  1790     if (blue) {
  1791         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1792     }
  1793     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1794         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1795     } else {
  1796         return 0;
  1797     }
  1798 }
  1799 
  1800 int
  1801 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  1802                                             Uint16 * green,
  1803                                             Uint16 * blue)
  1804 {
  1805     CHECK_WINDOW_MAGIC(window, -1);
  1806 
  1807     if (!window->gamma) {
  1808         int i;
  1809 
  1810         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  1811         if (!window->gamma) {
  1812             SDL_OutOfMemory();
  1813             return -1;
  1814         }
  1815         window->saved_gamma = window->gamma + 3*256;
  1816 
  1817         if (_this->GetWindowGammaRamp) {
  1818             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  1819                 return -1;
  1820             }
  1821         } else {
  1822             /* Create an identity gamma ramp */
  1823             for (i = 0; i < 256; ++i) {
  1824                 Uint16 value = (Uint16)((i << 8) | i);
  1825 
  1826                 window->gamma[0*256+i] = value;
  1827                 window->gamma[1*256+i] = value;
  1828                 window->gamma[2*256+i] = value;
  1829             }
  1830         }
  1831         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  1832     }
  1833 
  1834     if (red) {
  1835         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  1836     }
  1837     if (green) {
  1838         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  1839     }
  1840     if (blue) {
  1841         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  1842     }
  1843     return 0;
  1844 }
  1845 
  1846 static void
  1847 SDL_UpdateWindowGrab(SDL_Window * window)
  1848 {
  1849     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1850         _this->SetWindowGrab(_this, window);
  1851     }
  1852 }
  1853 
  1854 void
  1855 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  1856 {
  1857     CHECK_WINDOW_MAGIC(window, );
  1858 
  1859     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  1860         return;
  1861     }
  1862     if (grabbed) {
  1863         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1864     } else {
  1865         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1866     }
  1867     SDL_UpdateWindowGrab(window);
  1868 }
  1869 
  1870 SDL_bool
  1871 SDL_GetWindowGrab(SDL_Window * window)
  1872 {
  1873     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  1874 
  1875     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1876 }
  1877 
  1878 void
  1879 SDL_OnWindowShown(SDL_Window * window)
  1880 {
  1881     SDL_OnWindowRestored(window);
  1882 }
  1883 
  1884 void
  1885 SDL_OnWindowHidden(SDL_Window * window)
  1886 {
  1887     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1888 }
  1889 
  1890 void
  1891 SDL_OnWindowResized(SDL_Window * window)
  1892 {
  1893     window->surface_valid = SDL_FALSE;
  1894     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  1895 }
  1896 
  1897 void
  1898 SDL_OnWindowMinimized(SDL_Window * window)
  1899 {
  1900     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1901 }
  1902 
  1903 void
  1904 SDL_OnWindowRestored(SDL_Window * window)
  1905 {
  1906     SDL_RaiseWindow(window);
  1907 
  1908     if (FULLSCREEN_VISIBLE(window)) {
  1909         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1910     }
  1911 }
  1912 
  1913 void
  1914 SDL_OnWindowFocusGained(SDL_Window * window)
  1915 {
  1916     if (window->gamma && _this->SetWindowGammaRamp) {
  1917         _this->SetWindowGammaRamp(_this, window, window->gamma);
  1918     }
  1919 
  1920     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
  1921         _this->SetWindowGrab) {
  1922         _this->SetWindowGrab(_this, window);
  1923     }
  1924 }
  1925 
  1926 void
  1927 SDL_OnWindowFocusLost(SDL_Window * window)
  1928 {
  1929     if (window->gamma && _this->SetWindowGammaRamp) {
  1930         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  1931     }
  1932 
  1933     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
  1934         _this->SetWindowGrab) {
  1935         _this->SetWindowGrab(_this, window);
  1936     }
  1937 
  1938     /* If we're fullscreen on a single-head system and lose focus, minimize */
  1939     if ((window->flags & SDL_WINDOW_FULLSCREEN) && _this->num_displays == 1) {
  1940         SDL_MinimizeWindow(window);
  1941     }
  1942 }
  1943 
  1944 SDL_Window *
  1945 SDL_GetFocusWindow(void)
  1946 {
  1947     SDL_Window *window;
  1948 
  1949     if (!_this) {
  1950         return NULL;
  1951     }
  1952     for (window = _this->windows; window; window = window->next) {
  1953         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1954             return window;
  1955         }
  1956     }
  1957     return NULL;
  1958 }
  1959 
  1960 void
  1961 SDL_DestroyWindow(SDL_Window * window)
  1962 {
  1963     SDL_VideoDisplay *display;
  1964 
  1965     CHECK_WINDOW_MAGIC(window, );
  1966 
  1967     /* Restore video mode, etc. */
  1968     SDL_HideWindow(window);
  1969 
  1970     /* Make sure this window no longer has focus */
  1971     if (SDL_GetKeyboardFocus() == window) {
  1972         SDL_SetKeyboardFocus(NULL);
  1973     }
  1974     if (SDL_GetMouseFocus() == window) {
  1975         SDL_SetMouseFocus(NULL);
  1976     }
  1977 
  1978     /* make no context current if this is the current context window. */
  1979     if (window->flags & SDL_WINDOW_OPENGL) {
  1980         if (_this->current_glwin == window) {
  1981             SDL_GL_MakeCurrent(window, NULL);
  1982         }
  1983     }
  1984 
  1985     if (window->surface) {
  1986         window->surface->flags &= ~SDL_DONTFREE;
  1987         SDL_FreeSurface(window->surface);
  1988     }
  1989     if (_this->DestroyWindowFramebuffer) {
  1990         _this->DestroyWindowFramebuffer(_this, window);
  1991     }
  1992     if (_this->DestroyWindow) {
  1993         _this->DestroyWindow(_this, window);
  1994     }
  1995     if (window->flags & SDL_WINDOW_OPENGL) {
  1996         SDL_GL_UnloadLibrary();
  1997     }
  1998 
  1999     display = SDL_GetDisplayForWindow(window);
  2000     if (display->fullscreen_window == window) {
  2001         display->fullscreen_window = NULL;
  2002     }
  2003 
  2004     /* Now invalidate magic */
  2005     window->magic = NULL;
  2006 
  2007     /* Free memory associated with the window */
  2008     if (window->title) {
  2009         SDL_free(window->title);
  2010     }
  2011     if (window->gamma) {
  2012         SDL_free(window->gamma);
  2013     }
  2014     while (window->data) {
  2015         SDL_WindowUserData *data = window->data;
  2016 
  2017         window->data = data->next;
  2018         SDL_free(data->name);
  2019         SDL_free(data);
  2020     }
  2021 
  2022     /* Unlink the window from the list */
  2023     if (window->next) {
  2024         window->next->prev = window->prev;
  2025     }
  2026     if (window->prev) {
  2027         window->prev->next = window->next;
  2028     } else {
  2029         _this->windows = window->next;
  2030     }
  2031 
  2032     SDL_free(window);
  2033 }
  2034 
  2035 SDL_bool
  2036 SDL_IsScreenSaverEnabled()
  2037 {
  2038     if (!_this) {
  2039         return SDL_TRUE;
  2040     }
  2041     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2042 }
  2043 
  2044 void
  2045 SDL_EnableScreenSaver()
  2046 {
  2047     if (!_this) {
  2048         return;
  2049     }
  2050     if (!_this->suspend_screensaver) {
  2051         return;
  2052     }
  2053     _this->suspend_screensaver = SDL_FALSE;
  2054     if (_this->SuspendScreenSaver) {
  2055         _this->SuspendScreenSaver(_this);
  2056     }
  2057 }
  2058 
  2059 void
  2060 SDL_DisableScreenSaver()
  2061 {
  2062     if (!_this) {
  2063         return;
  2064     }
  2065     if (_this->suspend_screensaver) {
  2066         return;
  2067     }
  2068     _this->suspend_screensaver = SDL_TRUE;
  2069     if (_this->SuspendScreenSaver) {
  2070         _this->SuspendScreenSaver(_this);
  2071     }
  2072 }
  2073 
  2074 void
  2075 SDL_VideoQuit(void)
  2076 {
  2077     int i, j;
  2078 
  2079     if (!_this) {
  2080         return;
  2081     }
  2082 
  2083     /* Halt event processing before doing anything else */
  2084     SDL_QuitQuit();
  2085     SDL_MouseQuit();
  2086     SDL_KeyboardQuit();
  2087     SDL_StopEventLoop();
  2088 
  2089     SDL_EnableScreenSaver();
  2090 
  2091     /* Clean up the system video */
  2092     while (_this->windows) {
  2093         SDL_DestroyWindow(_this->windows);
  2094     }
  2095     _this->VideoQuit(_this);
  2096 
  2097     for (i = _this->num_displays; i--;) {
  2098         SDL_VideoDisplay *display = &_this->displays[i];
  2099         for (j = display->num_display_modes; j--;) {
  2100             if (display->display_modes[j].driverdata) {
  2101                 SDL_free(display->display_modes[j].driverdata);
  2102                 display->display_modes[j].driverdata = NULL;
  2103             }
  2104         }
  2105         if (display->display_modes) {
  2106             SDL_free(display->display_modes);
  2107             display->display_modes = NULL;
  2108         }
  2109         if (display->desktop_mode.driverdata) {
  2110             SDL_free(display->desktop_mode.driverdata);
  2111             display->desktop_mode.driverdata = NULL;
  2112         }
  2113         if (display->driverdata) {
  2114             SDL_free(display->driverdata);
  2115             display->driverdata = NULL;
  2116         }
  2117     }
  2118     if (_this->displays) {
  2119         SDL_free(_this->displays);
  2120         _this->displays = NULL;
  2121     }
  2122     if (_this->clipboard_text) {
  2123         SDL_free(_this->clipboard_text);
  2124         _this->clipboard_text = NULL;
  2125     }
  2126     _this->free(_this);
  2127     _this = NULL;
  2128 }
  2129 
  2130 int
  2131 SDL_GL_LoadLibrary(const char *path)
  2132 {
  2133     int retval;
  2134 
  2135     if (!_this) {
  2136         SDL_UninitializedVideo();
  2137         return -1;
  2138     }
  2139     if (_this->gl_config.driver_loaded) {
  2140         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2141             SDL_SetError("OpenGL library already loaded");
  2142             return -1;
  2143         }
  2144         retval = 0;
  2145     } else {
  2146         if (!_this->GL_LoadLibrary) {
  2147             SDL_SetError("No dynamic GL support in video driver");
  2148             return -1;
  2149         }
  2150         retval = _this->GL_LoadLibrary(_this, path);
  2151     }
  2152     if (retval == 0) {
  2153         ++_this->gl_config.driver_loaded;
  2154     }
  2155     return (retval);
  2156 }
  2157 
  2158 void *
  2159 SDL_GL_GetProcAddress(const char *proc)
  2160 {
  2161     void *func;
  2162 
  2163     if (!_this) {
  2164         SDL_UninitializedVideo();
  2165         return NULL;
  2166     }
  2167     func = NULL;
  2168     if (_this->GL_GetProcAddress) {
  2169         if (_this->gl_config.driver_loaded) {
  2170             func = _this->GL_GetProcAddress(_this, proc);
  2171         } else {
  2172             SDL_SetError("No GL driver has been loaded");
  2173         }
  2174     } else {
  2175         SDL_SetError("No dynamic GL support in video driver");
  2176     }
  2177     return func;
  2178 }
  2179 
  2180 void
  2181 SDL_GL_UnloadLibrary(void)
  2182 {
  2183     if (!_this) {
  2184         SDL_UninitializedVideo();
  2185         return;
  2186     }
  2187     if (_this->gl_config.driver_loaded > 0) {
  2188         if (--_this->gl_config.driver_loaded > 0) {
  2189             return;
  2190         }
  2191         if (_this->GL_UnloadLibrary) {
  2192             _this->GL_UnloadLibrary(_this);
  2193         }
  2194     }
  2195 }
  2196 
  2197 SDL_bool
  2198 SDL_GL_ExtensionSupported(const char *extension)
  2199 {
  2200 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2201     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2202     const char *extensions;
  2203     const char *start;
  2204     const char *where, *terminator;
  2205 
  2206     /* Extension names should not have spaces. */
  2207     where = SDL_strchr(extension, ' ');
  2208     if (where || *extension == '\0') {
  2209         return SDL_FALSE;
  2210     }
  2211     /* See if there's an environment variable override */
  2212     start = SDL_getenv(extension);
  2213     if (start && *start == '0') {
  2214         return SDL_FALSE;
  2215     }
  2216     /* Lookup the available extensions */
  2217     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2218     if (glGetStringFunc) {
  2219         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2220     } else {
  2221         extensions = NULL;
  2222     }
  2223     if (!extensions) {
  2224         return SDL_FALSE;
  2225     }
  2226     /*
  2227      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2228      * extensions string. Don't be fooled by sub-strings, etc.
  2229      */
  2230 
  2231     start = extensions;
  2232 
  2233     for (;;) {
  2234         where = SDL_strstr(start, extension);
  2235         if (!where)
  2236             break;
  2237 
  2238         terminator = where + SDL_strlen(extension);
  2239         if (where == start || *(where - 1) == ' ')
  2240             if (*terminator == ' ' || *terminator == '\0')
  2241                 return SDL_TRUE;
  2242 
  2243         start = terminator;
  2244     }
  2245     return SDL_FALSE;
  2246 #else
  2247     return SDL_FALSE;
  2248 #endif
  2249 }
  2250 
  2251 int
  2252 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2253 {
  2254 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2255     int retval;
  2256 
  2257     if (!_this) {
  2258         SDL_UninitializedVideo();
  2259         return -1;
  2260     }
  2261     retval = 0;
  2262     switch (attr) {
  2263     case SDL_GL_RED_SIZE:
  2264         _this->gl_config.red_size = value;
  2265         break;
  2266     case SDL_GL_GREEN_SIZE:
  2267         _this->gl_config.green_size = value;
  2268         break;
  2269     case SDL_GL_BLUE_SIZE:
  2270         _this->gl_config.blue_size = value;
  2271         break;
  2272     case SDL_GL_ALPHA_SIZE:
  2273         _this->gl_config.alpha_size = value;
  2274         break;
  2275     case SDL_GL_DOUBLEBUFFER:
  2276         _this->gl_config.double_buffer = value;
  2277         break;
  2278     case SDL_GL_BUFFER_SIZE:
  2279         _this->gl_config.buffer_size = value;
  2280         break;
  2281     case SDL_GL_DEPTH_SIZE:
  2282         _this->gl_config.depth_size = value;
  2283         break;
  2284     case SDL_GL_STENCIL_SIZE:
  2285         _this->gl_config.stencil_size = value;
  2286         break;
  2287     case SDL_GL_ACCUM_RED_SIZE:
  2288         _this->gl_config.accum_red_size = value;
  2289         break;
  2290     case SDL_GL_ACCUM_GREEN_SIZE:
  2291         _this->gl_config.accum_green_size = value;
  2292         break;
  2293     case SDL_GL_ACCUM_BLUE_SIZE:
  2294         _this->gl_config.accum_blue_size = value;
  2295         break;
  2296     case SDL_GL_ACCUM_ALPHA_SIZE:
  2297         _this->gl_config.accum_alpha_size = value;
  2298         break;
  2299     case SDL_GL_STEREO:
  2300         _this->gl_config.stereo = value;
  2301         break;
  2302     case SDL_GL_MULTISAMPLEBUFFERS:
  2303         _this->gl_config.multisamplebuffers = value;
  2304         break;
  2305     case SDL_GL_MULTISAMPLESAMPLES:
  2306         _this->gl_config.multisamplesamples = value;
  2307         break;
  2308     case SDL_GL_ACCELERATED_VISUAL:
  2309         _this->gl_config.accelerated = value;
  2310         break;
  2311     case SDL_GL_RETAINED_BACKING:
  2312         _this->gl_config.retained_backing = value;
  2313         break;
  2314     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2315         _this->gl_config.major_version = value;
  2316         break;
  2317     case SDL_GL_CONTEXT_MINOR_VERSION:
  2318         _this->gl_config.minor_version = value;
  2319         break;
  2320     case SDL_GL_CONTEXT_EGL:
  2321         _this->gl_config.use_egl = value;
  2322         break;
  2323     case SDL_GL_CONTEXT_FLAGS:
  2324         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2325 		      SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2326 		      SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2327 		      SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2328 	    SDL_SetError("Unknown OpenGL context flag %d", value);
  2329 	    retval = -1;
  2330 	    break;
  2331 	}
  2332         _this->gl_config.flags = value;
  2333         break;
  2334     case SDL_GL_CONTEXT_PROFILE_MASK:
  2335         if( value != 0 &&
  2336 	    value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2337 	    value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2338 	    value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2339 	    SDL_SetError("Unknown OpenGL context profile %d", value);
  2340 	    retval = -1;
  2341 	    break;
  2342 	}
  2343         _this->gl_config.profile_mask = value;
  2344         break;
  2345     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2346         _this->gl_config.share_with_current_context = value;
  2347 	break;
  2348     default:
  2349         SDL_SetError("Unknown OpenGL attribute");
  2350         retval = -1;
  2351         break;
  2352     }
  2353     return retval;
  2354 #else
  2355     SDL_Unsupported();
  2356     return -1;
  2357 #endif /* SDL_VIDEO_OPENGL */
  2358 }
  2359 
  2360 int
  2361 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2362 {
  2363 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2364     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2365     GLenum(APIENTRY * glGetErrorFunc) (void);
  2366     GLenum attrib = 0;
  2367     GLenum error = 0;
  2368 
  2369     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2370     if (!glGetIntegervFunc) {
  2371         return -1;
  2372     }
  2373 
  2374     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2375     if (!glGetErrorFunc) {
  2376         return -1;
  2377     }
  2378 
  2379     /* Clear value in any case */
  2380     *value = 0;
  2381 
  2382     switch (attr) {
  2383     case SDL_GL_RED_SIZE:
  2384         attrib = GL_RED_BITS;
  2385         break;
  2386     case SDL_GL_BLUE_SIZE:
  2387         attrib = GL_BLUE_BITS;
  2388         break;
  2389     case SDL_GL_GREEN_SIZE:
  2390         attrib = GL_GREEN_BITS;
  2391         break;
  2392     case SDL_GL_ALPHA_SIZE:
  2393         attrib = GL_ALPHA_BITS;
  2394         break;
  2395     case SDL_GL_DOUBLEBUFFER:
  2396 #if SDL_VIDEO_OPENGL
  2397         attrib = GL_DOUBLEBUFFER;
  2398         break;
  2399 #else
  2400         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2401         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2402         /* SDL driver must set proper value after initialization              */
  2403         *value = _this->gl_config.double_buffer;
  2404         return 0;
  2405 #endif
  2406     case SDL_GL_DEPTH_SIZE:
  2407         attrib = GL_DEPTH_BITS;
  2408         break;
  2409     case SDL_GL_STENCIL_SIZE:
  2410         attrib = GL_STENCIL_BITS;
  2411         break;
  2412 #if SDL_VIDEO_OPENGL
  2413     case SDL_GL_ACCUM_RED_SIZE:
  2414         attrib = GL_ACCUM_RED_BITS;
  2415         break;
  2416     case SDL_GL_ACCUM_GREEN_SIZE:
  2417         attrib = GL_ACCUM_GREEN_BITS;
  2418         break;
  2419     case SDL_GL_ACCUM_BLUE_SIZE:
  2420         attrib = GL_ACCUM_BLUE_BITS;
  2421         break;
  2422     case SDL_GL_ACCUM_ALPHA_SIZE:
  2423         attrib = GL_ACCUM_ALPHA_BITS;
  2424         break;
  2425     case SDL_GL_STEREO:
  2426         attrib = GL_STEREO;
  2427         break;
  2428 #else
  2429     case SDL_GL_ACCUM_RED_SIZE:
  2430     case SDL_GL_ACCUM_GREEN_SIZE:
  2431     case SDL_GL_ACCUM_BLUE_SIZE:
  2432     case SDL_GL_ACCUM_ALPHA_SIZE:
  2433     case SDL_GL_STEREO:
  2434         /* none of these are supported in OpenGL ES */
  2435         *value = 0;
  2436         return 0;
  2437 #endif
  2438     case SDL_GL_MULTISAMPLEBUFFERS:
  2439 #if SDL_VIDEO_OPENGL
  2440         attrib = GL_SAMPLE_BUFFERS_ARB;
  2441 #else
  2442         attrib = GL_SAMPLE_BUFFERS;
  2443 #endif
  2444         break;
  2445     case SDL_GL_MULTISAMPLESAMPLES:
  2446 #if SDL_VIDEO_OPENGL
  2447         attrib = GL_SAMPLES_ARB;
  2448 #else
  2449         attrib = GL_SAMPLES;
  2450 #endif
  2451         break;
  2452     case SDL_GL_BUFFER_SIZE:
  2453         {
  2454             GLint bits = 0;
  2455             GLint component;
  2456 
  2457             /*
  2458              * there doesn't seem to be a single flag in OpenGL
  2459              * for this!
  2460              */
  2461             glGetIntegervFunc(GL_RED_BITS, &component);
  2462             bits += component;
  2463             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2464             bits += component;
  2465             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2466             bits += component;
  2467             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2468             bits += component;
  2469 
  2470             *value = bits;
  2471             return 0;
  2472         }
  2473     case SDL_GL_ACCELERATED_VISUAL:
  2474         {
  2475             /* FIXME: How do we get this information? */
  2476             *value = (_this->gl_config.accelerated != 0);
  2477             return 0;
  2478         }
  2479     case SDL_GL_RETAINED_BACKING:
  2480         {
  2481             *value = _this->gl_config.retained_backing;
  2482             return 0;
  2483         }
  2484     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2485         {
  2486             *value = _this->gl_config.major_version;
  2487             return 0;
  2488         }
  2489     case SDL_GL_CONTEXT_MINOR_VERSION:
  2490         {
  2491             *value = _this->gl_config.minor_version;
  2492             return 0;
  2493         }
  2494     case SDL_GL_CONTEXT_EGL:
  2495         {
  2496             *value = _this->gl_config.use_egl;
  2497             return 0;
  2498         }
  2499     case SDL_GL_CONTEXT_FLAGS:
  2500         {
  2501             *value = _this->gl_config.flags;
  2502             return 0;
  2503         }
  2504     case SDL_GL_CONTEXT_PROFILE_MASK:
  2505         {
  2506             *value = _this->gl_config.profile_mask;
  2507             return 0;
  2508         }
  2509     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2510         {
  2511             *value = _this->gl_config.share_with_current_context;
  2512             return 0;
  2513         }
  2514     default:
  2515         SDL_SetError("Unknown OpenGL attribute");
  2516         return -1;
  2517     }
  2518 
  2519     glGetIntegervFunc(attrib, (GLint *) value);
  2520     error = glGetErrorFunc();
  2521     if (error != GL_NO_ERROR) {
  2522         switch (error) {
  2523         case GL_INVALID_ENUM:
  2524             {
  2525                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2526             }
  2527             break;
  2528         case GL_INVALID_VALUE:
  2529             {
  2530                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2531             }
  2532             break;
  2533         default:
  2534             {
  2535                 SDL_SetError("OpenGL error: %08X", error);
  2536             }
  2537             break;
  2538         }
  2539         return -1;
  2540     }
  2541     return 0;
  2542 #else
  2543     SDL_Unsupported();
  2544     return -1;
  2545 #endif /* SDL_VIDEO_OPENGL */
  2546 }
  2547 
  2548 SDL_GLContext
  2549 SDL_GL_CreateContext(SDL_Window * window)
  2550 {
  2551     SDL_GLContext ctx = NULL;
  2552     CHECK_WINDOW_MAGIC(window, NULL);
  2553 
  2554     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2555         SDL_SetError("The specified window isn't an OpenGL window");
  2556         return NULL;
  2557     }
  2558 
  2559     ctx = _this->GL_CreateContext(_this, window);
  2560 
  2561     /* Creating a context is assumed to make it current in the SDL driver. */
  2562     _this->current_glwin = window;
  2563     _this->current_glctx = ctx;
  2564 
  2565     return ctx;
  2566 }
  2567 
  2568 int
  2569 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2570 {
  2571     int retval;
  2572 
  2573     CHECK_WINDOW_MAGIC(window, -1);
  2574 
  2575     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2576         SDL_SetError("The specified window isn't an OpenGL window");
  2577         return -1;
  2578     }
  2579     if (!ctx) {
  2580         window = NULL;
  2581     }
  2582 
  2583     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
  2584         retval = 0;  /* we're already current. */
  2585     } else {
  2586         retval = _this->GL_MakeCurrent(_this, window, ctx);
  2587         if (retval == 0) {
  2588             _this->current_glwin = window;
  2589             _this->current_glctx = ctx;
  2590         }
  2591     }
  2592 
  2593     return retval;
  2594 }
  2595 
  2596 int
  2597 SDL_GL_SetSwapInterval(int interval)
  2598 {
  2599     if (!_this) {
  2600         SDL_UninitializedVideo();
  2601         return -1;
  2602     } else if (_this->current_glctx == NULL) {
  2603         SDL_SetError("No OpenGL context has been made current");
  2604         return -1;
  2605     } else if (_this->GL_SetSwapInterval) {
  2606         return _this->GL_SetSwapInterval(_this, interval);
  2607     } else {
  2608         SDL_SetError("Setting the swap interval is not supported");
  2609         return -1;
  2610     }
  2611 }
  2612 
  2613 int
  2614 SDL_GL_GetSwapInterval(void)
  2615 {
  2616     if (!_this) {
  2617         return 0;
  2618     } else if (_this->current_glctx == NULL) {
  2619         return 0;
  2620     } else if (_this->GL_GetSwapInterval) {
  2621         return _this->GL_GetSwapInterval(_this);
  2622     } else {
  2623         return 0;
  2624     }
  2625 }
  2626 
  2627 void
  2628 SDL_GL_SwapWindow(SDL_Window * window)
  2629 {
  2630     CHECK_WINDOW_MAGIC(window, );
  2631 
  2632     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2633         SDL_SetError("The specified window isn't an OpenGL window");
  2634         return;
  2635     }
  2636     _this->GL_SwapWindow(_this, window);
  2637 }
  2638 
  2639 void
  2640 SDL_GL_DeleteContext(SDL_GLContext context)
  2641 {
  2642     if (!_this || !context) {
  2643         return;
  2644     }
  2645     _this->GL_MakeCurrent(_this, NULL, NULL);
  2646     _this->GL_DeleteContext(_this, context);
  2647 }
  2648 
  2649 #if 0                           // FIXME
  2650 /*
  2651  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2652  * & 2 for alpha channel.
  2653  */
  2654 static void
  2655 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2656 {
  2657     int x, y;
  2658     Uint32 colorkey;
  2659 #define SET_MASKBIT(icon, x, y, mask) \
  2660 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2661 
  2662     colorkey = icon->format->colorkey;
  2663     switch (icon->format->BytesPerPixel) {
  2664     case 1:
  2665         {
  2666             Uint8 *pixels;
  2667             for (y = 0; y < icon->h; ++y) {
  2668                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2669                 for (x = 0; x < icon->w; ++x) {
  2670                     if (*pixels++ == colorkey) {
  2671                         SET_MASKBIT(icon, x, y, mask);
  2672                     }
  2673                 }
  2674             }
  2675         }
  2676         break;
  2677 
  2678     case 2:
  2679         {
  2680             Uint16 *pixels;
  2681             for (y = 0; y < icon->h; ++y) {
  2682                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2683                 for (x = 0; x < icon->w; ++x) {
  2684                     if ((flags & 1) && *pixels == colorkey) {
  2685                         SET_MASKBIT(icon, x, y, mask);
  2686                     } else if ((flags & 2)
  2687                                && (*pixels & icon->format->Amask) == 0) {
  2688                         SET_MASKBIT(icon, x, y, mask);
  2689                     }
  2690                     pixels++;
  2691                 }
  2692             }
  2693         }
  2694         break;
  2695 
  2696     case 4:
  2697         {
  2698             Uint32 *pixels;
  2699             for (y = 0; y < icon->h; ++y) {
  2700                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2701                 for (x = 0; x < icon->w; ++x) {
  2702                     if ((flags & 1) && *pixels == colorkey) {
  2703                         SET_MASKBIT(icon, x, y, mask);
  2704                     } else if ((flags & 2)
  2705                                && (*pixels & icon->format->Amask) == 0) {
  2706                         SET_MASKBIT(icon, x, y, mask);
  2707                     }
  2708                     pixels++;
  2709                 }
  2710             }
  2711         }
  2712         break;
  2713     }
  2714 }
  2715 
  2716 /*
  2717  * Sets the window manager icon for the display window.
  2718  */
  2719 void
  2720 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2721 {
  2722     if (icon && _this->SetIcon) {
  2723         /* Generate a mask if necessary, and create the icon! */
  2724         if (mask == NULL) {
  2725             int mask_len = icon->h * (icon->w + 7) / 8;
  2726             int flags = 0;
  2727             mask = (Uint8 *) SDL_malloc(mask_len);
  2728             if (mask == NULL) {
  2729                 return;
  2730             }
  2731             SDL_memset(mask, ~0, mask_len);
  2732             if (icon->flags & SDL_SRCCOLORKEY)
  2733                 flags |= 1;
  2734             if (icon->flags & SDL_SRCALPHA)
  2735                 flags |= 2;
  2736             if (flags) {
  2737                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2738             }
  2739             _this->SetIcon(_this, icon, mask);
  2740             SDL_free(mask);
  2741         } else {
  2742             _this->SetIcon(_this, icon, mask);
  2743         }
  2744     }
  2745 }
  2746 #endif
  2747 
  2748 SDL_bool
  2749 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2750 {
  2751     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2752 
  2753     if (!info) {
  2754         return SDL_FALSE;
  2755     }
  2756     info->subsystem = SDL_SYSWM_UNKNOWN;
  2757 
  2758     if (!_this->GetWindowWMInfo) {
  2759         return SDL_FALSE;
  2760     }
  2761     return (_this->GetWindowWMInfo(_this, window, info));
  2762 }
  2763 
  2764 void
  2765 SDL_StartTextInput(void)
  2766 {
  2767     if (_this && _this->StartTextInput) {
  2768         _this->StartTextInput(_this);
  2769     }
  2770     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2771     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2772 }
  2773 
  2774 void
  2775 SDL_StopTextInput(void)
  2776 {
  2777     if (_this && _this->StopTextInput) {
  2778         _this->StopTextInput(_this);
  2779     }
  2780     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2781     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2782 }
  2783 
  2784 void
  2785 SDL_SetTextInputRect(SDL_Rect *rect)
  2786 {
  2787     if (_this && _this->SetTextInputRect) {
  2788         _this->SetTextInputRect(_this, rect);
  2789     }
  2790 }
  2791 
  2792 SDL_bool
  2793 SDL_HasScreenKeyboardSupport(SDL_Window *window)
  2794 {
  2795     if (window && _this && _this->SDL_HasScreenKeyboardSupport) {
  2796         return _this->SDL_HasScreenKeyboardSupport(_this, window);
  2797     }
  2798     return SDL_FALSE;
  2799 }
  2800 
  2801 int
  2802 SDL_ShowScreenKeyboard(SDL_Window *window)
  2803 {
  2804     if (window && _this && _this->SDL_ShowScreenKeyboard) {
  2805         return _this->SDL_ShowScreenKeyboard(_this, window);
  2806     }
  2807     return -1;
  2808 }
  2809 
  2810 int
  2811 SDL_HideScreenKeyboard(SDL_Window *window)
  2812 {
  2813     if (window && _this && _this->SDL_HideScreenKeyboard) {
  2814         return _this->SDL_HideScreenKeyboard(_this, window);
  2815     }
  2816     return -1;
  2817 }
  2818 
  2819 int
  2820 SDL_ToggleScreenKeyboard(SDL_Window *window)
  2821 {
  2822     if (window && _this && _this->SDL_ToggleScreenKeyboard) {
  2823         return _this->SDL_ToggleScreenKeyboard(_this, window);
  2824     }
  2825     return -1;
  2826 }
  2827 
  2828 SDL_bool
  2829 SDL_IsScreenKeyboardShown(SDL_Window *window)
  2830 {
  2831     if (window && _this && _this->SDL_IsScreenKeyboardShown) {
  2832         return _this->SDL_IsScreenKeyboardShown(_this, window);
  2833     }
  2834     return SDL_FALSE;
  2835 }
  2836 
  2837 /* vi: set ts=4 sw=4 expandtab: */