src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 10 Sep 2012 20:25:55 -0700
changeset 6418 9c12f2c8057b
parent 6393 a773384edf20
child 6419 b75e82af5ef1
permissions -rwxr-xr-x
Fixed issue where the context couldn't be unbound after the window is shown because the current context was already marked as NULL. (Thanks to John McDonald for tracking that down!)
     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->desktop_mode.w;
   627         rect->h = display->desktop_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_SetWindowSize(SDL_Window * window, int w, int h)
  1495 {
  1496     CHECK_WINDOW_MAGIC(window, );
  1497 
  1498     /* FIXME: Should this change fullscreen modes? */
  1499     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1500         window->w = w;
  1501         window->h = h;
  1502         if (_this->SetWindowSize) {
  1503             _this->SetWindowSize(_this, window);
  1504         }
  1505         if (window->w == w && window->h == h) {
  1506             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1507             SDL_OnWindowResized(window);
  1508         }
  1509     }
  1510 }
  1511 
  1512 void
  1513 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1514 {
  1515     int dummy;
  1516 
  1517     if (!w) {
  1518         w = &dummy;
  1519     }
  1520     if (!h) {
  1521         h = &dummy;
  1522     }
  1523 
  1524     *w = 0;
  1525     *h = 0;
  1526 
  1527     CHECK_WINDOW_MAGIC(window, );
  1528 
  1529     if (_this && window && window->magic == &_this->window_magic) {
  1530         if (w) {
  1531             *w = window->w;
  1532         }
  1533         if (h) {
  1534             *h = window->h;
  1535         }
  1536     } else {
  1537         if (w) {
  1538             *w = 0;
  1539         }
  1540         if (h) {
  1541             *h = 0;
  1542         }
  1543     }
  1544 }
  1545 
  1546 void
  1547 SDL_ShowWindow(SDL_Window * window)
  1548 {
  1549     CHECK_WINDOW_MAGIC(window, );
  1550 
  1551     if (window->flags & SDL_WINDOW_SHOWN) {
  1552         return;
  1553     }
  1554 
  1555     if (_this->ShowWindow) {
  1556         _this->ShowWindow(_this, window);
  1557     }
  1558     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1559 }
  1560 
  1561 void
  1562 SDL_HideWindow(SDL_Window * window)
  1563 {
  1564     CHECK_WINDOW_MAGIC(window, );
  1565 
  1566     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1567         return;
  1568     }
  1569 
  1570     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1571 
  1572     if (_this->HideWindow) {
  1573         _this->HideWindow(_this, window);
  1574     }
  1575     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1576 }
  1577 
  1578 void
  1579 SDL_RaiseWindow(SDL_Window * window)
  1580 {
  1581     CHECK_WINDOW_MAGIC(window, );
  1582 
  1583     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1584         return;
  1585     }
  1586     if (_this->RaiseWindow) {
  1587         _this->RaiseWindow(_this, window);
  1588     }
  1589 }
  1590 
  1591 void
  1592 SDL_MaximizeWindow(SDL_Window * window)
  1593 {
  1594     CHECK_WINDOW_MAGIC(window, );
  1595 
  1596     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1597         return;
  1598     }
  1599 
  1600     if (_this->MaximizeWindow) {
  1601         _this->MaximizeWindow(_this, window);
  1602     }
  1603 }
  1604 
  1605 void
  1606 SDL_MinimizeWindow(SDL_Window * window)
  1607 {
  1608     CHECK_WINDOW_MAGIC(window, );
  1609 
  1610     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1611         return;
  1612     }
  1613 
  1614     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1615 
  1616     if (_this->MinimizeWindow) {
  1617         _this->MinimizeWindow(_this, window);
  1618     }
  1619 }
  1620 
  1621 void
  1622 SDL_RestoreWindow(SDL_Window * window)
  1623 {
  1624     CHECK_WINDOW_MAGIC(window, );
  1625 
  1626     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1627         return;
  1628     }
  1629 
  1630     if (_this->RestoreWindow) {
  1631         _this->RestoreWindow(_this, window);
  1632     }
  1633 }
  1634 
  1635 int
  1636 SDL_SetWindowFullscreen(SDL_Window * window, SDL_bool fullscreen)
  1637 {
  1638     CHECK_WINDOW_MAGIC(window, -1);
  1639 
  1640     if (!!fullscreen == !!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1641         return 0;
  1642     }
  1643     if (fullscreen) {
  1644         window->flags |= SDL_WINDOW_FULLSCREEN;
  1645     } else {
  1646         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1647     }
  1648     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1649 
  1650     return 0;
  1651 }
  1652 
  1653 static SDL_Surface *
  1654 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1655 {
  1656     Uint32 format;
  1657     void *pixels;
  1658     int pitch;
  1659     int bpp;
  1660     Uint32 Rmask, Gmask, Bmask, Amask;
  1661 
  1662     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1663         return NULL;
  1664     }
  1665 
  1666     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1667         return NULL;
  1668     }
  1669 
  1670     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1671         return NULL;
  1672     }
  1673 
  1674     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1675 }
  1676 
  1677 SDL_Surface *
  1678 SDL_GetWindowSurface(SDL_Window * window)
  1679 {
  1680     CHECK_WINDOW_MAGIC(window, NULL);
  1681 
  1682     if (!window->surface_valid) {
  1683         if (window->surface) {
  1684             window->surface->flags &= ~SDL_DONTFREE;
  1685             SDL_FreeSurface(window->surface);
  1686         }
  1687         window->surface = SDL_CreateWindowFramebuffer(window);
  1688         if (window->surface) {
  1689             window->surface_valid = SDL_TRUE;
  1690             window->surface->flags |= SDL_DONTFREE;
  1691         }
  1692     }
  1693     return window->surface;
  1694 }
  1695 
  1696 int
  1697 SDL_UpdateWindowSurface(SDL_Window * window)
  1698 {
  1699     SDL_Rect full_rect;
  1700 
  1701     CHECK_WINDOW_MAGIC(window, -1);
  1702 
  1703     full_rect.x = 0;
  1704     full_rect.y = 0;
  1705     full_rect.w = window->w;
  1706     full_rect.h = window->h;
  1707     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1708 }
  1709 
  1710 int
  1711 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
  1712                              int numrects)
  1713 {
  1714     CHECK_WINDOW_MAGIC(window, -1);
  1715 
  1716     if (!window->surface_valid) {
  1717         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1718         return -1;
  1719     }
  1720 
  1721     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1722 }
  1723 
  1724 int
  1725 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1726 {
  1727     Uint16 ramp[256];
  1728     int status;
  1729 
  1730     CHECK_WINDOW_MAGIC(window, -1);
  1731 
  1732     SDL_CalculateGammaRamp(brightness, ramp);
  1733     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1734     if (status == 0) {
  1735         window->brightness = brightness;
  1736     }
  1737     return status;
  1738 }
  1739 
  1740 float
  1741 SDL_GetWindowBrightness(SDL_Window * window)
  1742 {
  1743     CHECK_WINDOW_MAGIC(window, 1.0f);
  1744 
  1745     return window->brightness;
  1746 }
  1747 
  1748 int
  1749 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1750                                             const Uint16 * green,
  1751                                             const Uint16 * blue)
  1752 {
  1753     CHECK_WINDOW_MAGIC(window, -1);
  1754 
  1755     if (!_this->SetWindowGammaRamp) {
  1756         SDL_Unsupported();
  1757         return -1;
  1758     }
  1759 
  1760     if (!window->gamma) {
  1761         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1762             return -1;
  1763         }
  1764     }
  1765 
  1766     if (red) {
  1767         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1768     }
  1769     if (green) {
  1770         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1771     }
  1772     if (blue) {
  1773         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1774     }
  1775     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1776         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1777     } else {
  1778         return 0;
  1779     }
  1780 }
  1781 
  1782 int
  1783 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  1784                                             Uint16 * green,
  1785                                             Uint16 * blue)
  1786 {
  1787     CHECK_WINDOW_MAGIC(window, -1);
  1788 
  1789     if (!window->gamma) {
  1790         int i;
  1791 
  1792         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  1793         if (!window->gamma) {
  1794             SDL_OutOfMemory();
  1795             return -1;
  1796         }
  1797         window->saved_gamma = window->gamma + 3*256;
  1798 
  1799         if (_this->GetWindowGammaRamp) {
  1800             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  1801                 return -1;
  1802             }
  1803         } else {
  1804             /* Create an identity gamma ramp */
  1805             for (i = 0; i < 256; ++i) {
  1806                 Uint16 value = (Uint16)((i << 8) | i);
  1807 
  1808                 window->gamma[0*256+i] = value;
  1809                 window->gamma[1*256+i] = value;
  1810                 window->gamma[2*256+i] = value;
  1811             }
  1812         }
  1813         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  1814     }
  1815 
  1816     if (red) {
  1817         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  1818     }
  1819     if (green) {
  1820         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  1821     }
  1822     if (blue) {
  1823         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  1824     }
  1825     return 0;
  1826 }
  1827 
  1828 static void
  1829 SDL_UpdateWindowGrab(SDL_Window * window)
  1830 {
  1831     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1832         _this->SetWindowGrab(_this, window);
  1833     }
  1834 }
  1835 
  1836 void
  1837 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  1838 {
  1839     CHECK_WINDOW_MAGIC(window, );
  1840 
  1841     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  1842         return;
  1843     }
  1844     if (grabbed) {
  1845         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1846     } else {
  1847         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1848     }
  1849     SDL_UpdateWindowGrab(window);
  1850 }
  1851 
  1852 SDL_bool
  1853 SDL_GetWindowGrab(SDL_Window * window)
  1854 {
  1855     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  1856 
  1857     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1858 }
  1859 
  1860 void
  1861 SDL_OnWindowShown(SDL_Window * window)
  1862 {
  1863     SDL_OnWindowRestored(window);
  1864 }
  1865 
  1866 void
  1867 SDL_OnWindowHidden(SDL_Window * window)
  1868 {
  1869     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1870 }
  1871 
  1872 void
  1873 SDL_OnWindowResized(SDL_Window * window)
  1874 {
  1875     window->surface_valid = SDL_FALSE;
  1876     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  1877 }
  1878 
  1879 void
  1880 SDL_OnWindowMinimized(SDL_Window * window)
  1881 {
  1882     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1883 }
  1884 
  1885 void
  1886 SDL_OnWindowRestored(SDL_Window * window)
  1887 {
  1888     SDL_RaiseWindow(window);
  1889 
  1890     if (FULLSCREEN_VISIBLE(window)) {
  1891         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1892     }
  1893 
  1894     /* This needs to be done on iOS to rebind the nscontext to the view,
  1895        and (hopefully) doesn't hurt on other systems.
  1896     */
  1897     if (window == _this->current_glwin) {
  1898         _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
  1899     }
  1900 }
  1901 
  1902 void
  1903 SDL_OnWindowFocusGained(SDL_Window * window)
  1904 {
  1905     if (window->gamma && _this->SetWindowGammaRamp) {
  1906         _this->SetWindowGammaRamp(_this, window, window->gamma);
  1907     }
  1908 
  1909     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
  1910         _this->SetWindowGrab) {
  1911         _this->SetWindowGrab(_this, window);
  1912     }
  1913 }
  1914 
  1915 void
  1916 SDL_OnWindowFocusLost(SDL_Window * window)
  1917 {
  1918     if (window->gamma && _this->SetWindowGammaRamp) {
  1919         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  1920     }
  1921 
  1922     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
  1923         _this->SetWindowGrab) {
  1924         _this->SetWindowGrab(_this, window);
  1925     }
  1926 
  1927     /* If we're fullscreen on a single-head system and lose focus, minimize */
  1928     if ((window->flags & SDL_WINDOW_FULLSCREEN) && _this->num_displays == 1) {
  1929         SDL_MinimizeWindow(window);
  1930     }
  1931 }
  1932 
  1933 SDL_Window *
  1934 SDL_GetFocusWindow(void)
  1935 {
  1936     SDL_Window *window;
  1937 
  1938     if (!_this) {
  1939         return NULL;
  1940     }
  1941     for (window = _this->windows; window; window = window->next) {
  1942         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1943             return window;
  1944         }
  1945     }
  1946     return NULL;
  1947 }
  1948 
  1949 void
  1950 SDL_DestroyWindow(SDL_Window * window)
  1951 {
  1952     SDL_VideoDisplay *display;
  1953 
  1954     CHECK_WINDOW_MAGIC(window, );
  1955 
  1956     /* Restore video mode, etc. */
  1957     SDL_HideWindow(window);
  1958 
  1959     /* Make sure this window no longer has focus */
  1960     if (SDL_GetKeyboardFocus() == window) {
  1961         SDL_SetKeyboardFocus(NULL);
  1962     }
  1963     if (SDL_GetMouseFocus() == window) {
  1964         SDL_SetMouseFocus(NULL);
  1965     }
  1966 
  1967     /* make no context current if this is the current context window. */
  1968     if (window->flags & SDL_WINDOW_OPENGL) {
  1969         if (_this->current_glwin == window) {
  1970             SDL_GL_MakeCurrent(NULL, NULL);
  1971         }
  1972     }
  1973 
  1974     if (window->surface) {
  1975         window->surface->flags &= ~SDL_DONTFREE;
  1976         SDL_FreeSurface(window->surface);
  1977     }
  1978     if (_this->DestroyWindowFramebuffer) {
  1979         _this->DestroyWindowFramebuffer(_this, window);
  1980     }
  1981     if (_this->DestroyWindow) {
  1982         _this->DestroyWindow(_this, window);
  1983     }
  1984     if (window->flags & SDL_WINDOW_OPENGL) {
  1985         SDL_GL_UnloadLibrary();
  1986     }
  1987 
  1988     display = SDL_GetDisplayForWindow(window);
  1989     if (display->fullscreen_window == window) {
  1990         display->fullscreen_window = NULL;
  1991     }
  1992 
  1993     /* Now invalidate magic */
  1994     window->magic = NULL;
  1995 
  1996     /* Free memory associated with the window */
  1997     if (window->title) {
  1998         SDL_free(window->title);
  1999     }
  2000     if (window->gamma) {
  2001         SDL_free(window->gamma);
  2002     }
  2003     while (window->data) {
  2004         SDL_WindowUserData *data = window->data;
  2005 
  2006         window->data = data->next;
  2007         SDL_free(data->name);
  2008         SDL_free(data);
  2009     }
  2010 
  2011     /* Unlink the window from the list */
  2012     if (window->next) {
  2013         window->next->prev = window->prev;
  2014     }
  2015     if (window->prev) {
  2016         window->prev->next = window->next;
  2017     } else {
  2018         _this->windows = window->next;
  2019     }
  2020 
  2021     SDL_free(window);
  2022 }
  2023 
  2024 SDL_bool
  2025 SDL_IsScreenSaverEnabled()
  2026 {
  2027     if (!_this) {
  2028         return SDL_TRUE;
  2029     }
  2030     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2031 }
  2032 
  2033 void
  2034 SDL_EnableScreenSaver()
  2035 {
  2036     if (!_this) {
  2037         return;
  2038     }
  2039     if (!_this->suspend_screensaver) {
  2040         return;
  2041     }
  2042     _this->suspend_screensaver = SDL_FALSE;
  2043     if (_this->SuspendScreenSaver) {
  2044         _this->SuspendScreenSaver(_this);
  2045     }
  2046 }
  2047 
  2048 void
  2049 SDL_DisableScreenSaver()
  2050 {
  2051     if (!_this) {
  2052         return;
  2053     }
  2054     if (_this->suspend_screensaver) {
  2055         return;
  2056     }
  2057     _this->suspend_screensaver = SDL_TRUE;
  2058     if (_this->SuspendScreenSaver) {
  2059         _this->SuspendScreenSaver(_this);
  2060     }
  2061 }
  2062 
  2063 void
  2064 SDL_VideoQuit(void)
  2065 {
  2066     int i, j;
  2067 
  2068     if (!_this) {
  2069         return;
  2070     }
  2071 
  2072     /* Halt event processing before doing anything else */
  2073     SDL_QuitQuit();
  2074     SDL_MouseQuit();
  2075     SDL_KeyboardQuit();
  2076     SDL_StopEventLoop();
  2077 
  2078     SDL_EnableScreenSaver();
  2079 
  2080     /* Clean up the system video */
  2081     while (_this->windows) {
  2082         SDL_DestroyWindow(_this->windows);
  2083     }
  2084     _this->VideoQuit(_this);
  2085 
  2086     for (i = _this->num_displays; i--;) {
  2087         SDL_VideoDisplay *display = &_this->displays[i];
  2088         for (j = display->num_display_modes; j--;) {
  2089             if (display->display_modes[j].driverdata) {
  2090                 SDL_free(display->display_modes[j].driverdata);
  2091                 display->display_modes[j].driverdata = NULL;
  2092             }
  2093         }
  2094         if (display->display_modes) {
  2095             SDL_free(display->display_modes);
  2096             display->display_modes = NULL;
  2097         }
  2098         if (display->desktop_mode.driverdata) {
  2099             SDL_free(display->desktop_mode.driverdata);
  2100             display->desktop_mode.driverdata = NULL;
  2101         }
  2102         if (display->driverdata) {
  2103             SDL_free(display->driverdata);
  2104             display->driverdata = NULL;
  2105         }
  2106     }
  2107     if (_this->displays) {
  2108         SDL_free(_this->displays);
  2109         _this->displays = NULL;
  2110     }
  2111     if (_this->clipboard_text) {
  2112         SDL_free(_this->clipboard_text);
  2113         _this->clipboard_text = NULL;
  2114     }
  2115     _this->free(_this);
  2116     _this = NULL;
  2117 }
  2118 
  2119 int
  2120 SDL_GL_LoadLibrary(const char *path)
  2121 {
  2122     int retval;
  2123 
  2124     if (!_this) {
  2125         SDL_UninitializedVideo();
  2126         return -1;
  2127     }
  2128     if (_this->gl_config.driver_loaded) {
  2129         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2130             SDL_SetError("OpenGL library already loaded");
  2131             return -1;
  2132         }
  2133         retval = 0;
  2134     } else {
  2135         if (!_this->GL_LoadLibrary) {
  2136             SDL_SetError("No dynamic GL support in video driver");
  2137             return -1;
  2138         }
  2139         retval = _this->GL_LoadLibrary(_this, path);
  2140     }
  2141     if (retval == 0) {
  2142         ++_this->gl_config.driver_loaded;
  2143     }
  2144     return (retval);
  2145 }
  2146 
  2147 void *
  2148 SDL_GL_GetProcAddress(const char *proc)
  2149 {
  2150     void *func;
  2151 
  2152     if (!_this) {
  2153         SDL_UninitializedVideo();
  2154         return NULL;
  2155     }
  2156     func = NULL;
  2157     if (_this->GL_GetProcAddress) {
  2158         if (_this->gl_config.driver_loaded) {
  2159             func = _this->GL_GetProcAddress(_this, proc);
  2160         } else {
  2161             SDL_SetError("No GL driver has been loaded");
  2162         }
  2163     } else {
  2164         SDL_SetError("No dynamic GL support in video driver");
  2165     }
  2166     return func;
  2167 }
  2168 
  2169 void
  2170 SDL_GL_UnloadLibrary(void)
  2171 {
  2172     if (!_this) {
  2173         SDL_UninitializedVideo();
  2174         return;
  2175     }
  2176     if (_this->gl_config.driver_loaded > 0) {
  2177         if (--_this->gl_config.driver_loaded > 0) {
  2178             return;
  2179         }
  2180         if (_this->GL_UnloadLibrary) {
  2181             _this->GL_UnloadLibrary(_this);
  2182         }
  2183     }
  2184 }
  2185 
  2186 SDL_bool
  2187 SDL_GL_ExtensionSupported(const char *extension)
  2188 {
  2189 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2190     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2191     const char *extensions;
  2192     const char *start;
  2193     const char *where, *terminator;
  2194 
  2195     /* Extension names should not have spaces. */
  2196     where = SDL_strchr(extension, ' ');
  2197     if (where || *extension == '\0') {
  2198         return SDL_FALSE;
  2199     }
  2200     /* See if there's an environment variable override */
  2201     start = SDL_getenv(extension);
  2202     if (start && *start == '0') {
  2203         return SDL_FALSE;
  2204     }
  2205     /* Lookup the available extensions */
  2206     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2207     if (glGetStringFunc) {
  2208         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2209     } else {
  2210         extensions = NULL;
  2211     }
  2212     if (!extensions) {
  2213         return SDL_FALSE;
  2214     }
  2215     /*
  2216      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2217      * extensions string. Don't be fooled by sub-strings, etc.
  2218      */
  2219 
  2220     start = extensions;
  2221 
  2222     for (;;) {
  2223         where = SDL_strstr(start, extension);
  2224         if (!where)
  2225             break;
  2226 
  2227         terminator = where + SDL_strlen(extension);
  2228         if (where == start || *(where - 1) == ' ')
  2229             if (*terminator == ' ' || *terminator == '\0')
  2230                 return SDL_TRUE;
  2231 
  2232         start = terminator;
  2233     }
  2234     return SDL_FALSE;
  2235 #else
  2236     return SDL_FALSE;
  2237 #endif
  2238 }
  2239 
  2240 int
  2241 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2242 {
  2243 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2244     int retval;
  2245 
  2246     if (!_this) {
  2247         SDL_UninitializedVideo();
  2248         return -1;
  2249     }
  2250     retval = 0;
  2251     switch (attr) {
  2252     case SDL_GL_RED_SIZE:
  2253         _this->gl_config.red_size = value;
  2254         break;
  2255     case SDL_GL_GREEN_SIZE:
  2256         _this->gl_config.green_size = value;
  2257         break;
  2258     case SDL_GL_BLUE_SIZE:
  2259         _this->gl_config.blue_size = value;
  2260         break;
  2261     case SDL_GL_ALPHA_SIZE:
  2262         _this->gl_config.alpha_size = value;
  2263         break;
  2264     case SDL_GL_DOUBLEBUFFER:
  2265         _this->gl_config.double_buffer = value;
  2266         break;
  2267     case SDL_GL_BUFFER_SIZE:
  2268         _this->gl_config.buffer_size = value;
  2269         break;
  2270     case SDL_GL_DEPTH_SIZE:
  2271         _this->gl_config.depth_size = value;
  2272         break;
  2273     case SDL_GL_STENCIL_SIZE:
  2274         _this->gl_config.stencil_size = value;
  2275         break;
  2276     case SDL_GL_ACCUM_RED_SIZE:
  2277         _this->gl_config.accum_red_size = value;
  2278         break;
  2279     case SDL_GL_ACCUM_GREEN_SIZE:
  2280         _this->gl_config.accum_green_size = value;
  2281         break;
  2282     case SDL_GL_ACCUM_BLUE_SIZE:
  2283         _this->gl_config.accum_blue_size = value;
  2284         break;
  2285     case SDL_GL_ACCUM_ALPHA_SIZE:
  2286         _this->gl_config.accum_alpha_size = value;
  2287         break;
  2288     case SDL_GL_STEREO:
  2289         _this->gl_config.stereo = value;
  2290         break;
  2291     case SDL_GL_MULTISAMPLEBUFFERS:
  2292         _this->gl_config.multisamplebuffers = value;
  2293         break;
  2294     case SDL_GL_MULTISAMPLESAMPLES:
  2295         _this->gl_config.multisamplesamples = value;
  2296         break;
  2297     case SDL_GL_ACCELERATED_VISUAL:
  2298         _this->gl_config.accelerated = value;
  2299         break;
  2300     case SDL_GL_RETAINED_BACKING:
  2301         _this->gl_config.retained_backing = value;
  2302         break;
  2303     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2304         _this->gl_config.major_version = value;
  2305         break;
  2306     case SDL_GL_CONTEXT_MINOR_VERSION:
  2307         _this->gl_config.minor_version = value;
  2308         break;
  2309     case SDL_GL_CONTEXT_EGL:
  2310         _this->gl_config.use_egl = value;
  2311         break;
  2312     case SDL_GL_CONTEXT_FLAGS:
  2313         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2314 		      SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2315 		      SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2316 		      SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2317 	    SDL_SetError("Unknown OpenGL context flag %d", value);
  2318 	    retval = -1;
  2319 	    break;
  2320 	}
  2321         _this->gl_config.flags = value;
  2322         break;
  2323     case SDL_GL_CONTEXT_PROFILE_MASK:
  2324         if( value != 0 &&
  2325 	    value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2326 	    value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2327 	    value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2328 	    SDL_SetError("Unknown OpenGL context profile %d", value);
  2329 	    retval = -1;
  2330 	    break;
  2331 	}
  2332         _this->gl_config.profile_mask = value;
  2333         break;
  2334     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2335         _this->gl_config.share_with_current_context = value;
  2336 	break;
  2337     default:
  2338         SDL_SetError("Unknown OpenGL attribute");
  2339         retval = -1;
  2340         break;
  2341     }
  2342     return retval;
  2343 #else
  2344     SDL_Unsupported();
  2345     return -1;
  2346 #endif /* SDL_VIDEO_OPENGL */
  2347 }
  2348 
  2349 int
  2350 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2351 {
  2352 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2353     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2354     GLenum(APIENTRY * glGetErrorFunc) (void);
  2355     GLenum attrib = 0;
  2356     GLenum error = 0;
  2357 
  2358     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2359     if (!glGetIntegervFunc) {
  2360         return -1;
  2361     }
  2362 
  2363     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2364     if (!glGetErrorFunc) {
  2365         return -1;
  2366     }
  2367 
  2368     /* Clear value in any case */
  2369     *value = 0;
  2370 
  2371     switch (attr) {
  2372     case SDL_GL_RED_SIZE:
  2373         attrib = GL_RED_BITS;
  2374         break;
  2375     case SDL_GL_BLUE_SIZE:
  2376         attrib = GL_BLUE_BITS;
  2377         break;
  2378     case SDL_GL_GREEN_SIZE:
  2379         attrib = GL_GREEN_BITS;
  2380         break;
  2381     case SDL_GL_ALPHA_SIZE:
  2382         attrib = GL_ALPHA_BITS;
  2383         break;
  2384     case SDL_GL_DOUBLEBUFFER:
  2385 #if SDL_VIDEO_OPENGL
  2386         attrib = GL_DOUBLEBUFFER;
  2387         break;
  2388 #else
  2389         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2390         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2391         /* SDL driver must set proper value after initialization              */
  2392         *value = _this->gl_config.double_buffer;
  2393         return 0;
  2394 #endif
  2395     case SDL_GL_DEPTH_SIZE:
  2396         attrib = GL_DEPTH_BITS;
  2397         break;
  2398     case SDL_GL_STENCIL_SIZE:
  2399         attrib = GL_STENCIL_BITS;
  2400         break;
  2401 #if SDL_VIDEO_OPENGL
  2402     case SDL_GL_ACCUM_RED_SIZE:
  2403         attrib = GL_ACCUM_RED_BITS;
  2404         break;
  2405     case SDL_GL_ACCUM_GREEN_SIZE:
  2406         attrib = GL_ACCUM_GREEN_BITS;
  2407         break;
  2408     case SDL_GL_ACCUM_BLUE_SIZE:
  2409         attrib = GL_ACCUM_BLUE_BITS;
  2410         break;
  2411     case SDL_GL_ACCUM_ALPHA_SIZE:
  2412         attrib = GL_ACCUM_ALPHA_BITS;
  2413         break;
  2414     case SDL_GL_STEREO:
  2415         attrib = GL_STEREO;
  2416         break;
  2417 #else
  2418     case SDL_GL_ACCUM_RED_SIZE:
  2419     case SDL_GL_ACCUM_GREEN_SIZE:
  2420     case SDL_GL_ACCUM_BLUE_SIZE:
  2421     case SDL_GL_ACCUM_ALPHA_SIZE:
  2422     case SDL_GL_STEREO:
  2423         /* none of these are supported in OpenGL ES */
  2424         *value = 0;
  2425         return 0;
  2426 #endif
  2427     case SDL_GL_MULTISAMPLEBUFFERS:
  2428 #if SDL_VIDEO_OPENGL
  2429         attrib = GL_SAMPLE_BUFFERS_ARB;
  2430 #else
  2431         attrib = GL_SAMPLE_BUFFERS;
  2432 #endif
  2433         break;
  2434     case SDL_GL_MULTISAMPLESAMPLES:
  2435 #if SDL_VIDEO_OPENGL
  2436         attrib = GL_SAMPLES_ARB;
  2437 #else
  2438         attrib = GL_SAMPLES;
  2439 #endif
  2440         break;
  2441     case SDL_GL_BUFFER_SIZE:
  2442         {
  2443             GLint bits = 0;
  2444             GLint component;
  2445 
  2446             /*
  2447              * there doesn't seem to be a single flag in OpenGL
  2448              * for this!
  2449              */
  2450             glGetIntegervFunc(GL_RED_BITS, &component);
  2451             bits += component;
  2452             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2453             bits += component;
  2454             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2455             bits += component;
  2456             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2457             bits += component;
  2458 
  2459             *value = bits;
  2460             return 0;
  2461         }
  2462     case SDL_GL_ACCELERATED_VISUAL:
  2463         {
  2464             /* FIXME: How do we get this information? */
  2465             *value = (_this->gl_config.accelerated != 0);
  2466             return 0;
  2467         }
  2468     case SDL_GL_RETAINED_BACKING:
  2469         {
  2470             *value = _this->gl_config.retained_backing;
  2471             return 0;
  2472         }
  2473     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2474         {
  2475             *value = _this->gl_config.major_version;
  2476             return 0;
  2477         }
  2478     case SDL_GL_CONTEXT_MINOR_VERSION:
  2479         {
  2480             *value = _this->gl_config.minor_version;
  2481             return 0;
  2482         }
  2483     case SDL_GL_CONTEXT_EGL:
  2484         {
  2485             *value = _this->gl_config.use_egl;
  2486             return 0;
  2487         }
  2488     case SDL_GL_CONTEXT_FLAGS:
  2489         {
  2490             *value = _this->gl_config.flags;
  2491             return 0;
  2492         }
  2493     case SDL_GL_CONTEXT_PROFILE_MASK:
  2494         {
  2495             *value = _this->gl_config.profile_mask;
  2496             return 0;
  2497         }
  2498     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2499         {
  2500             *value = _this->gl_config.share_with_current_context;
  2501             return 0;
  2502         }
  2503     default:
  2504         SDL_SetError("Unknown OpenGL attribute");
  2505         return -1;
  2506     }
  2507 
  2508     glGetIntegervFunc(attrib, (GLint *) value);
  2509     error = glGetErrorFunc();
  2510     if (error != GL_NO_ERROR) {
  2511         switch (error) {
  2512         case GL_INVALID_ENUM:
  2513             {
  2514                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2515             }
  2516             break;
  2517         case GL_INVALID_VALUE:
  2518             {
  2519                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2520             }
  2521             break;
  2522         default:
  2523             {
  2524                 SDL_SetError("OpenGL error: %08X", error);
  2525             }
  2526             break;
  2527         }
  2528         return -1;
  2529     }
  2530     return 0;
  2531 #else
  2532     SDL_Unsupported();
  2533     return -1;
  2534 #endif /* SDL_VIDEO_OPENGL */
  2535 }
  2536 
  2537 SDL_GLContext
  2538 SDL_GL_CreateContext(SDL_Window * window)
  2539 {
  2540     SDL_GLContext ctx = NULL;
  2541     CHECK_WINDOW_MAGIC(window, NULL);
  2542 
  2543     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2544         SDL_SetError("The specified window isn't an OpenGL window");
  2545         return NULL;
  2546     }
  2547 
  2548     ctx = _this->GL_CreateContext(_this, window);
  2549 
  2550     /* Creating a context is assumed to make it current in the SDL driver. */
  2551     _this->current_glwin = window;
  2552     _this->current_glctx = ctx;
  2553 
  2554     return ctx;
  2555 }
  2556 
  2557 int
  2558 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2559 {
  2560     int retval;
  2561 
  2562     CHECK_WINDOW_MAGIC(window, -1);
  2563 
  2564     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2565         SDL_SetError("The specified window isn't an OpenGL window");
  2566         return -1;
  2567     }
  2568     if (!ctx) {
  2569         window = NULL;
  2570     }
  2571 
  2572     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
  2573         retval = 0;  /* we're already current. */
  2574     } else {
  2575         retval = _this->GL_MakeCurrent(_this, window, ctx);
  2576         if (retval == 0) {
  2577             _this->current_glwin = window;
  2578             _this->current_glctx = ctx;
  2579         }
  2580     }
  2581 
  2582     return retval;
  2583 }
  2584 
  2585 int
  2586 SDL_GL_SetSwapInterval(int interval)
  2587 {
  2588     if (!_this) {
  2589         SDL_UninitializedVideo();
  2590         return -1;
  2591     } else if (_this->current_glctx == NULL) {
  2592         SDL_SetError("No OpenGL context has been made current");
  2593         return -1;
  2594     } else if (_this->GL_SetSwapInterval) {
  2595         return _this->GL_SetSwapInterval(_this, interval);
  2596     } else {
  2597         SDL_SetError("Setting the swap interval is not supported");
  2598         return -1;
  2599     }
  2600 }
  2601 
  2602 int
  2603 SDL_GL_GetSwapInterval(void)
  2604 {
  2605     if (!_this) {
  2606         return 0;
  2607     } else if (_this->current_glctx == NULL) {
  2608         return 0;
  2609     } else if (_this->GL_GetSwapInterval) {
  2610         return _this->GL_GetSwapInterval(_this);
  2611     } else {
  2612         return 0;
  2613     }
  2614 }
  2615 
  2616 void
  2617 SDL_GL_SwapWindow(SDL_Window * window)
  2618 {
  2619     CHECK_WINDOW_MAGIC(window, );
  2620 
  2621     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2622         SDL_SetError("The specified window isn't an OpenGL window");
  2623         return;
  2624     }
  2625     _this->GL_SwapWindow(_this, window);
  2626 }
  2627 
  2628 void
  2629 SDL_GL_DeleteContext(SDL_GLContext context)
  2630 {
  2631     if (!_this || !_this->gl_data || !context) {
  2632         return;
  2633     }
  2634     _this->GL_MakeCurrent(_this, NULL, NULL);
  2635     _this->GL_DeleteContext(_this, context);
  2636 }
  2637 
  2638 #if 0                           // FIXME
  2639 /*
  2640  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2641  * & 2 for alpha channel.
  2642  */
  2643 static void
  2644 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2645 {
  2646     int x, y;
  2647     Uint32 colorkey;
  2648 #define SET_MASKBIT(icon, x, y, mask) \
  2649 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2650 
  2651     colorkey = icon->format->colorkey;
  2652     switch (icon->format->BytesPerPixel) {
  2653     case 1:
  2654         {
  2655             Uint8 *pixels;
  2656             for (y = 0; y < icon->h; ++y) {
  2657                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2658                 for (x = 0; x < icon->w; ++x) {
  2659                     if (*pixels++ == colorkey) {
  2660                         SET_MASKBIT(icon, x, y, mask);
  2661                     }
  2662                 }
  2663             }
  2664         }
  2665         break;
  2666 
  2667     case 2:
  2668         {
  2669             Uint16 *pixels;
  2670             for (y = 0; y < icon->h; ++y) {
  2671                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2672                 for (x = 0; x < icon->w; ++x) {
  2673                     if ((flags & 1) && *pixels == colorkey) {
  2674                         SET_MASKBIT(icon, x, y, mask);
  2675                     } else if ((flags & 2)
  2676                                && (*pixels & icon->format->Amask) == 0) {
  2677                         SET_MASKBIT(icon, x, y, mask);
  2678                     }
  2679                     pixels++;
  2680                 }
  2681             }
  2682         }
  2683         break;
  2684 
  2685     case 4:
  2686         {
  2687             Uint32 *pixels;
  2688             for (y = 0; y < icon->h; ++y) {
  2689                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2690                 for (x = 0; x < icon->w; ++x) {
  2691                     if ((flags & 1) && *pixels == colorkey) {
  2692                         SET_MASKBIT(icon, x, y, mask);
  2693                     } else if ((flags & 2)
  2694                                && (*pixels & icon->format->Amask) == 0) {
  2695                         SET_MASKBIT(icon, x, y, mask);
  2696                     }
  2697                     pixels++;
  2698                 }
  2699             }
  2700         }
  2701         break;
  2702     }
  2703 }
  2704 
  2705 /*
  2706  * Sets the window manager icon for the display window.
  2707  */
  2708 void
  2709 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2710 {
  2711     if (icon && _this->SetIcon) {
  2712         /* Generate a mask if necessary, and create the icon! */
  2713         if (mask == NULL) {
  2714             int mask_len = icon->h * (icon->w + 7) / 8;
  2715             int flags = 0;
  2716             mask = (Uint8 *) SDL_malloc(mask_len);
  2717             if (mask == NULL) {
  2718                 return;
  2719             }
  2720             SDL_memset(mask, ~0, mask_len);
  2721             if (icon->flags & SDL_SRCCOLORKEY)
  2722                 flags |= 1;
  2723             if (icon->flags & SDL_SRCALPHA)
  2724                 flags |= 2;
  2725             if (flags) {
  2726                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2727             }
  2728             _this->SetIcon(_this, icon, mask);
  2729             SDL_free(mask);
  2730         } else {
  2731             _this->SetIcon(_this, icon, mask);
  2732         }
  2733     }
  2734 }
  2735 #endif
  2736 
  2737 SDL_bool
  2738 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2739 {
  2740     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2741 
  2742     if (!info) {
  2743         return SDL_FALSE;
  2744     }
  2745     info->subsystem = SDL_SYSWM_UNKNOWN;
  2746 
  2747     if (!_this->GetWindowWMInfo) {
  2748         return SDL_FALSE;
  2749     }
  2750     return (_this->GetWindowWMInfo(_this, window, info));
  2751 }
  2752 
  2753 void
  2754 SDL_StartTextInput(void)
  2755 {
  2756     if (_this && _this->StartTextInput) {
  2757         _this->StartTextInput(_this);
  2758     }
  2759     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2760     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2761 }
  2762 
  2763 void
  2764 SDL_StopTextInput(void)
  2765 {
  2766     if (_this && _this->StopTextInput) {
  2767         _this->StopTextInput(_this);
  2768     }
  2769     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2770     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2771 }
  2772 
  2773 void
  2774 SDL_SetTextInputRect(SDL_Rect *rect)
  2775 {
  2776     if (_this && _this->SetTextInputRect) {
  2777         _this->SetTextInputRect(_this, rect);
  2778     }
  2779 }
  2780 
  2781 SDL_bool
  2782 SDL_HasScreenKeyboardSupport(SDL_Window *window)
  2783 {
  2784     if (window && _this && _this->SDL_HasScreenKeyboardSupport) {
  2785         return _this->SDL_HasScreenKeyboardSupport(_this, window);
  2786     }
  2787     return SDL_FALSE;
  2788 }
  2789 
  2790 int
  2791 SDL_ShowScreenKeyboard(SDL_Window *window)
  2792 {
  2793     if (window && _this && _this->SDL_ShowScreenKeyboard) {
  2794         return _this->SDL_ShowScreenKeyboard(_this, window);
  2795     }
  2796     return -1;
  2797 }
  2798 
  2799 int
  2800 SDL_HideScreenKeyboard(SDL_Window *window)
  2801 {
  2802     if (window && _this && _this->SDL_HideScreenKeyboard) {
  2803         return _this->SDL_HideScreenKeyboard(_this, window);
  2804     }
  2805     return -1;
  2806 }
  2807 
  2808 int
  2809 SDL_ToggleScreenKeyboard(SDL_Window *window)
  2810 {
  2811     if (window && _this && _this->SDL_ToggleScreenKeyboard) {
  2812         return _this->SDL_ToggleScreenKeyboard(_this, window);
  2813     }
  2814     return -1;
  2815 }
  2816 
  2817 SDL_bool
  2818 SDL_IsScreenKeyboardShown(SDL_Window *window)
  2819 {
  2820     if (window && _this && _this->SDL_IsScreenKeyboardShown) {
  2821         return _this->SDL_IsScreenKeyboardShown(_this, window);
  2822     }
  2823     return SDL_FALSE;
  2824 }
  2825 
  2826 /* vi: set ts=4 sw=4 expandtab: */