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