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