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