src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 14 Jan 2012 01:38:11 -0500
changeset 6214 b1a71f8189a6
parent 6188 e82023802002
child 6260 fd494c5f305b
permissions -rwxr-xr-x
Fixed bug 1238 - SDL_SetKeyboardFocus may send events to already destroyed windows

bastien.bouclet@gmail.com 2011-06-26 02:15:36 PDT

SDL_Keyboard::focus does not seem to be reset when the window that has focus is
destroyed, resulting in the following crash :

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