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