src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 20 Feb 2012 23:37:57 -0500
changeset 6296 b42657486c0d
parent 6266 a4be1e781020
child 6370 93187f7f7d5d
permissions -rwxr-xr-x
Add OpenGL 3.X context creation support

Matthias Bentrup 2011-10-30 03:58:24 PDT

I've updated the context creation patch to include the bugfixes by Martin
Schreiber and also included a profile bit to request a ES2 compatible profile.

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