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