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