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