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