src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 11 Aug 2012 10:15:59 -0700
changeset 6392 fa7eb111f994
parent 6382 64d54101773a
child 6393 a773384edf20
permissions -rwxr-xr-x
Fixed bug 1564 - SDL has no function to open a screen keyboard on Android.

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