src/video/SDL_video.c
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Mon, 22 Apr 2013 18:14:55 -0700
changeset 7089 257fc4e541e1
parent 7046 8d5636aafd1c
child 7091 ff07fad908f8
permissions -rw-r--r--
Send mouse leave updates for Windows and X11.

We now generate a final SDL_MOUSEMOTION before the cursor leaves the
window, followed by a SDL_WINDOWEVENT_LEAVE.
     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_OnWindowEnter(SDL_Window * window)
  2033 {
  2034     if (_this->OnWindowEnter) {
  2035         _this->OnWindowEnter(_this, window);
  2036     }
  2037 }
  2038 
  2039 void
  2040 SDL_OnWindowLeave(SDL_Window * window)
  2041 {
  2042 }
  2043 
  2044 void
  2045 SDL_OnWindowFocusGained(SDL_Window * window)
  2046 {
  2047     if (window->gamma && _this->SetWindowGammaRamp) {
  2048         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2049     }
  2050 
  2051     SDL_UpdateWindowGrab(window);
  2052 }
  2053 
  2054 static SDL_bool ShouldMinimizeOnFocusLoss()
  2055 {
  2056 	const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2057 	if (hint) {
  2058 		if (*hint == '0') {
  2059 			return SDL_FALSE;
  2060 		} else {
  2061 			return SDL_TRUE;
  2062 		}
  2063 	}
  2064 	return SDL_TRUE;
  2065 }
  2066 
  2067 void
  2068 SDL_OnWindowFocusLost(SDL_Window * window)
  2069 {
  2070     if (window->gamma && _this->SetWindowGammaRamp) {
  2071         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2072     }
  2073 
  2074     SDL_UpdateWindowGrab(window);
  2075 
  2076     /* If we're fullscreen on a single-head system and lose focus, minimize */
  2077 	 if ((window->flags & SDL_WINDOW_FULLSCREEN) && ShouldMinimizeOnFocusLoss() ) {
  2078 			SDL_MinimizeWindow(window);
  2079     }
  2080 }
  2081 
  2082 SDL_Window *
  2083 SDL_GetFocusWindow(void)
  2084 {
  2085     SDL_Window *window;
  2086 
  2087     if (!_this) {
  2088         return NULL;
  2089     }
  2090     for (window = _this->windows; window; window = window->next) {
  2091         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2092             return window;
  2093         }
  2094     }
  2095     return NULL;
  2096 }
  2097 
  2098 void
  2099 SDL_DestroyWindow(SDL_Window * window)
  2100 {
  2101     SDL_VideoDisplay *display;
  2102 
  2103     CHECK_WINDOW_MAGIC(window, );
  2104 
  2105     /* Restore video mode, etc. */
  2106     SDL_HideWindow(window);
  2107 
  2108     /* Make sure this window no longer has focus */
  2109     if (SDL_GetKeyboardFocus() == window) {
  2110         SDL_SetKeyboardFocus(NULL);
  2111     }
  2112     if (SDL_GetMouseFocus() == window) {
  2113         SDL_SetMouseFocus(NULL);
  2114     }
  2115 
  2116     /* make no context current if this is the current context window. */
  2117     if (window->flags & SDL_WINDOW_OPENGL) {
  2118         if (_this->current_glwin == window) {
  2119             SDL_GL_MakeCurrent(window, NULL);
  2120         }
  2121     }
  2122 
  2123     if (window->surface) {
  2124         window->surface->flags &= ~SDL_DONTFREE;
  2125         SDL_FreeSurface(window->surface);
  2126     }
  2127     if (_this->DestroyWindowFramebuffer) {
  2128         _this->DestroyWindowFramebuffer(_this, window);
  2129     }
  2130     if (_this->DestroyWindow) {
  2131         _this->DestroyWindow(_this, window);
  2132     }
  2133     if (window->flags & SDL_WINDOW_OPENGL) {
  2134         SDL_GL_UnloadLibrary();
  2135     }
  2136 
  2137     display = SDL_GetDisplayForWindow(window);
  2138     if (display->fullscreen_window == window) {
  2139         display->fullscreen_window = NULL;
  2140     }
  2141 
  2142     /* Now invalidate magic */
  2143     window->magic = NULL;
  2144 
  2145     /* Free memory associated with the window */
  2146     if (window->title) {
  2147         SDL_free(window->title);
  2148     }
  2149     if (window->gamma) {
  2150         SDL_free(window->gamma);
  2151     }
  2152     while (window->data) {
  2153         SDL_WindowUserData *data = window->data;
  2154 
  2155         window->data = data->next;
  2156         SDL_free(data->name);
  2157         SDL_free(data);
  2158     }
  2159 
  2160     /* Unlink the window from the list */
  2161     if (window->next) {
  2162         window->next->prev = window->prev;
  2163     }
  2164     if (window->prev) {
  2165         window->prev->next = window->next;
  2166     } else {
  2167         _this->windows = window->next;
  2168     }
  2169 
  2170     SDL_free(window);
  2171 }
  2172 
  2173 SDL_bool
  2174 SDL_IsScreenSaverEnabled()
  2175 {
  2176     if (!_this) {
  2177         return SDL_TRUE;
  2178     }
  2179     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2180 }
  2181 
  2182 void
  2183 SDL_EnableScreenSaver()
  2184 {
  2185     if (!_this) {
  2186         return;
  2187     }
  2188     if (!_this->suspend_screensaver) {
  2189         return;
  2190     }
  2191     _this->suspend_screensaver = SDL_FALSE;
  2192     if (_this->SuspendScreenSaver) {
  2193         _this->SuspendScreenSaver(_this);
  2194     }
  2195 }
  2196 
  2197 void
  2198 SDL_DisableScreenSaver()
  2199 {
  2200     if (!_this) {
  2201         return;
  2202     }
  2203     if (_this->suspend_screensaver) {
  2204         return;
  2205     }
  2206     _this->suspend_screensaver = SDL_TRUE;
  2207     if (_this->SuspendScreenSaver) {
  2208         _this->SuspendScreenSaver(_this);
  2209     }
  2210 }
  2211 
  2212 void
  2213 SDL_VideoQuit(void)
  2214 {
  2215     int i, j;
  2216 
  2217     if (!_this) {
  2218         return;
  2219     }
  2220 
  2221     /* Halt event processing before doing anything else */
  2222     SDL_QuitQuit();
  2223     SDL_MouseQuit();
  2224     SDL_KeyboardQuit();
  2225     SDL_StopEventLoop();
  2226 
  2227     SDL_EnableScreenSaver();
  2228 
  2229     /* Clean up the system video */
  2230     while (_this->windows) {
  2231         SDL_DestroyWindow(_this->windows);
  2232     }
  2233     _this->VideoQuit(_this);
  2234 
  2235     for (i = _this->num_displays; i--;) {
  2236         SDL_VideoDisplay *display = &_this->displays[i];
  2237         for (j = display->num_display_modes; j--;) {
  2238             if (display->display_modes[j].driverdata) {
  2239                 SDL_free(display->display_modes[j].driverdata);
  2240                 display->display_modes[j].driverdata = NULL;
  2241             }
  2242         }
  2243         if (display->display_modes) {
  2244             SDL_free(display->display_modes);
  2245             display->display_modes = NULL;
  2246         }
  2247         if (display->desktop_mode.driverdata) {
  2248             SDL_free(display->desktop_mode.driverdata);
  2249             display->desktop_mode.driverdata = NULL;
  2250         }
  2251         if (display->driverdata) {
  2252             SDL_free(display->driverdata);
  2253             display->driverdata = NULL;
  2254         }
  2255     }
  2256     if (_this->displays) {
  2257         for (i = 0; i < _this->num_displays; ++i) {
  2258             SDL_free(_this->displays[i].name);
  2259         }
  2260         SDL_free(_this->displays);
  2261         _this->displays = NULL;
  2262         _this->num_displays = 0;
  2263     }
  2264     if (_this->clipboard_text) {
  2265         SDL_free(_this->clipboard_text);
  2266         _this->clipboard_text = NULL;
  2267     }
  2268     _this->free(_this);
  2269     _this = NULL;
  2270 }
  2271 
  2272 int
  2273 SDL_GL_LoadLibrary(const char *path)
  2274 {
  2275     int retval;
  2276 
  2277     if (!_this) {
  2278         return SDL_UninitializedVideo();
  2279     }
  2280     if (_this->gl_config.driver_loaded) {
  2281         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2282             return SDL_SetError("OpenGL library already loaded");
  2283         }
  2284         retval = 0;
  2285     } else {
  2286         if (!_this->GL_LoadLibrary) {
  2287             return  SDL_SetError("No dynamic GL support in video driver");
  2288         }
  2289         retval = _this->GL_LoadLibrary(_this, path);
  2290     }
  2291     if (retval == 0) {
  2292         ++_this->gl_config.driver_loaded;
  2293     }
  2294     return (retval);
  2295 }
  2296 
  2297 void *
  2298 SDL_GL_GetProcAddress(const char *proc)
  2299 {
  2300     void *func;
  2301 
  2302     if (!_this) {
  2303         SDL_UninitializedVideo();
  2304         return NULL;
  2305     }
  2306     func = NULL;
  2307     if (_this->GL_GetProcAddress) {
  2308         if (_this->gl_config.driver_loaded) {
  2309             func = _this->GL_GetProcAddress(_this, proc);
  2310         } else {
  2311             SDL_SetError("No GL driver has been loaded");
  2312         }
  2313     } else {
  2314         SDL_SetError("No dynamic GL support in video driver");
  2315     }
  2316     return func;
  2317 }
  2318 
  2319 void
  2320 SDL_GL_UnloadLibrary(void)
  2321 {
  2322     if (!_this) {
  2323         SDL_UninitializedVideo();
  2324         return;
  2325     }
  2326     if (_this->gl_config.driver_loaded > 0) {
  2327         if (--_this->gl_config.driver_loaded > 0) {
  2328             return;
  2329         }
  2330         if (_this->GL_UnloadLibrary) {
  2331             _this->GL_UnloadLibrary(_this);
  2332         }
  2333     }
  2334 }
  2335 
  2336 SDL_bool
  2337 SDL_GL_ExtensionSupported(const char *extension)
  2338 {
  2339 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2340     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2341     const char *extensions;
  2342     const char *start;
  2343     const char *where, *terminator;
  2344 
  2345     /* Extension names should not have spaces. */
  2346     where = SDL_strchr(extension, ' ');
  2347     if (where || *extension == '\0') {
  2348         return SDL_FALSE;
  2349     }
  2350     /* See if there's an environment variable override */
  2351     start = SDL_getenv(extension);
  2352     if (start && *start == '0') {
  2353         return SDL_FALSE;
  2354     }
  2355     /* Lookup the available extensions */
  2356     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2357     if (glGetStringFunc) {
  2358         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2359     } else {
  2360         extensions = NULL;
  2361     }
  2362     if (!extensions) {
  2363         return SDL_FALSE;
  2364     }
  2365     /*
  2366      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2367      * extensions string. Don't be fooled by sub-strings, etc.
  2368      */
  2369 
  2370     start = extensions;
  2371 
  2372     for (;;) {
  2373         where = SDL_strstr(start, extension);
  2374         if (!where)
  2375             break;
  2376 
  2377         terminator = where + SDL_strlen(extension);
  2378         if (where == start || *(where - 1) == ' ')
  2379             if (*terminator == ' ' || *terminator == '\0')
  2380                 return SDL_TRUE;
  2381 
  2382         start = terminator;
  2383     }
  2384     return SDL_FALSE;
  2385 #else
  2386     return SDL_FALSE;
  2387 #endif
  2388 }
  2389 
  2390 int
  2391 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2392 {
  2393 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2394     int retval;
  2395 
  2396     if (!_this) {
  2397         return SDL_UninitializedVideo();
  2398     }
  2399     retval = 0;
  2400     switch (attr) {
  2401     case SDL_GL_RED_SIZE:
  2402         _this->gl_config.red_size = value;
  2403         break;
  2404     case SDL_GL_GREEN_SIZE:
  2405         _this->gl_config.green_size = value;
  2406         break;
  2407     case SDL_GL_BLUE_SIZE:
  2408         _this->gl_config.blue_size = value;
  2409         break;
  2410     case SDL_GL_ALPHA_SIZE:
  2411         _this->gl_config.alpha_size = value;
  2412         break;
  2413     case SDL_GL_DOUBLEBUFFER:
  2414         _this->gl_config.double_buffer = value;
  2415         break;
  2416     case SDL_GL_BUFFER_SIZE:
  2417         _this->gl_config.buffer_size = value;
  2418         break;
  2419     case SDL_GL_DEPTH_SIZE:
  2420         _this->gl_config.depth_size = value;
  2421         break;
  2422     case SDL_GL_STENCIL_SIZE:
  2423         _this->gl_config.stencil_size = value;
  2424         break;
  2425     case SDL_GL_ACCUM_RED_SIZE:
  2426         _this->gl_config.accum_red_size = value;
  2427         break;
  2428     case SDL_GL_ACCUM_GREEN_SIZE:
  2429         _this->gl_config.accum_green_size = value;
  2430         break;
  2431     case SDL_GL_ACCUM_BLUE_SIZE:
  2432         _this->gl_config.accum_blue_size = value;
  2433         break;
  2434     case SDL_GL_ACCUM_ALPHA_SIZE:
  2435         _this->gl_config.accum_alpha_size = value;
  2436         break;
  2437     case SDL_GL_STEREO:
  2438         _this->gl_config.stereo = value;
  2439         break;
  2440     case SDL_GL_MULTISAMPLEBUFFERS:
  2441         _this->gl_config.multisamplebuffers = value;
  2442         break;
  2443     case SDL_GL_MULTISAMPLESAMPLES:
  2444         _this->gl_config.multisamplesamples = value;
  2445         break;
  2446     case SDL_GL_ACCELERATED_VISUAL:
  2447         _this->gl_config.accelerated = value;
  2448         break;
  2449     case SDL_GL_RETAINED_BACKING:
  2450         _this->gl_config.retained_backing = value;
  2451         break;
  2452     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2453         _this->gl_config.major_version = value;
  2454         break;
  2455     case SDL_GL_CONTEXT_MINOR_VERSION:
  2456         _this->gl_config.minor_version = value;
  2457         break;
  2458     case SDL_GL_CONTEXT_EGL:
  2459         _this->gl_config.use_egl = value;
  2460         break;
  2461     case SDL_GL_CONTEXT_FLAGS:
  2462         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2463 		      SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2464 		      SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2465 		      SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2466 	    retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2467 	    break;
  2468 	}
  2469         _this->gl_config.flags = value;
  2470         break;
  2471     case SDL_GL_CONTEXT_PROFILE_MASK:
  2472         if( value != 0 &&
  2473 	    value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2474 	    value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2475 	    value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2476 	    retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2477 	    break;
  2478 	}
  2479         _this->gl_config.profile_mask = value;
  2480         break;
  2481     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2482         _this->gl_config.share_with_current_context = value;
  2483 	break;
  2484     default:
  2485         retval = SDL_SetError("Unknown OpenGL attribute");
  2486         break;
  2487     }
  2488     return retval;
  2489 #else
  2490     return SDL_Unsupported();
  2491 #endif /* SDL_VIDEO_OPENGL */
  2492 }
  2493 
  2494 int
  2495 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2496 {
  2497 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2498     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2499     GLenum(APIENTRY * glGetErrorFunc) (void);
  2500     GLenum attrib = 0;
  2501     GLenum error = 0;
  2502 
  2503     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2504     if (!glGetIntegervFunc) {
  2505         return -1;
  2506     }
  2507 
  2508     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2509     if (!glGetErrorFunc) {
  2510         return -1;
  2511     }
  2512 
  2513     /* Clear value in any case */
  2514     *value = 0;
  2515 
  2516     switch (attr) {
  2517     case SDL_GL_RED_SIZE:
  2518         attrib = GL_RED_BITS;
  2519         break;
  2520     case SDL_GL_BLUE_SIZE:
  2521         attrib = GL_BLUE_BITS;
  2522         break;
  2523     case SDL_GL_GREEN_SIZE:
  2524         attrib = GL_GREEN_BITS;
  2525         break;
  2526     case SDL_GL_ALPHA_SIZE:
  2527         attrib = GL_ALPHA_BITS;
  2528         break;
  2529     case SDL_GL_DOUBLEBUFFER:
  2530 #if SDL_VIDEO_OPENGL
  2531         attrib = GL_DOUBLEBUFFER;
  2532         break;
  2533 #else
  2534         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2535         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2536         /* SDL driver must set proper value after initialization              */
  2537         *value = _this->gl_config.double_buffer;
  2538         return 0;
  2539 #endif
  2540     case SDL_GL_DEPTH_SIZE:
  2541         attrib = GL_DEPTH_BITS;
  2542         break;
  2543     case SDL_GL_STENCIL_SIZE:
  2544         attrib = GL_STENCIL_BITS;
  2545         break;
  2546 #if SDL_VIDEO_OPENGL
  2547     case SDL_GL_ACCUM_RED_SIZE:
  2548         attrib = GL_ACCUM_RED_BITS;
  2549         break;
  2550     case SDL_GL_ACCUM_GREEN_SIZE:
  2551         attrib = GL_ACCUM_GREEN_BITS;
  2552         break;
  2553     case SDL_GL_ACCUM_BLUE_SIZE:
  2554         attrib = GL_ACCUM_BLUE_BITS;
  2555         break;
  2556     case SDL_GL_ACCUM_ALPHA_SIZE:
  2557         attrib = GL_ACCUM_ALPHA_BITS;
  2558         break;
  2559     case SDL_GL_STEREO:
  2560         attrib = GL_STEREO;
  2561         break;
  2562 #else
  2563     case SDL_GL_ACCUM_RED_SIZE:
  2564     case SDL_GL_ACCUM_GREEN_SIZE:
  2565     case SDL_GL_ACCUM_BLUE_SIZE:
  2566     case SDL_GL_ACCUM_ALPHA_SIZE:
  2567     case SDL_GL_STEREO:
  2568         /* none of these are supported in OpenGL ES */
  2569         *value = 0;
  2570         return 0;
  2571 #endif
  2572     case SDL_GL_MULTISAMPLEBUFFERS:
  2573 #if SDL_VIDEO_OPENGL
  2574         attrib = GL_SAMPLE_BUFFERS_ARB;
  2575 #else
  2576         attrib = GL_SAMPLE_BUFFERS;
  2577 #endif
  2578         break;
  2579     case SDL_GL_MULTISAMPLESAMPLES:
  2580 #if SDL_VIDEO_OPENGL
  2581         attrib = GL_SAMPLES_ARB;
  2582 #else
  2583         attrib = GL_SAMPLES;
  2584 #endif
  2585         break;
  2586     case SDL_GL_BUFFER_SIZE:
  2587         {
  2588             GLint bits = 0;
  2589             GLint component;
  2590 
  2591             /*
  2592              * there doesn't seem to be a single flag in OpenGL
  2593              * for this!
  2594              */
  2595             glGetIntegervFunc(GL_RED_BITS, &component);
  2596             bits += component;
  2597             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2598             bits += component;
  2599             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2600             bits += component;
  2601             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2602             bits += component;
  2603 
  2604             *value = bits;
  2605             return 0;
  2606         }
  2607     case SDL_GL_ACCELERATED_VISUAL:
  2608         {
  2609             /* FIXME: How do we get this information? */
  2610             *value = (_this->gl_config.accelerated != 0);
  2611             return 0;
  2612         }
  2613     case SDL_GL_RETAINED_BACKING:
  2614         {
  2615             *value = _this->gl_config.retained_backing;
  2616             return 0;
  2617         }
  2618     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2619         {
  2620             *value = _this->gl_config.major_version;
  2621             return 0;
  2622         }
  2623     case SDL_GL_CONTEXT_MINOR_VERSION:
  2624         {
  2625             *value = _this->gl_config.minor_version;
  2626             return 0;
  2627         }
  2628     case SDL_GL_CONTEXT_EGL:
  2629         {
  2630             *value = _this->gl_config.use_egl;
  2631             return 0;
  2632         }
  2633     case SDL_GL_CONTEXT_FLAGS:
  2634         {
  2635             *value = _this->gl_config.flags;
  2636             return 0;
  2637         }
  2638     case SDL_GL_CONTEXT_PROFILE_MASK:
  2639         {
  2640             *value = _this->gl_config.profile_mask;
  2641             return 0;
  2642         }
  2643     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2644         {
  2645             *value = _this->gl_config.share_with_current_context;
  2646             return 0;
  2647         }
  2648     default:
  2649         return SDL_SetError("Unknown OpenGL attribute");
  2650     }
  2651 
  2652     glGetIntegervFunc(attrib, (GLint *) value);
  2653     error = glGetErrorFunc();
  2654     if (error != GL_NO_ERROR) {
  2655         if (error == GL_INVALID_ENUM) {
  2656             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2657         } else if (error == GL_INVALID_VALUE) {
  2658             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2659         }
  2660         return SDL_SetError("OpenGL error: %08X", error);
  2661     }
  2662     return 0;
  2663 #else
  2664     return SDL_Unsupported();
  2665 #endif /* SDL_VIDEO_OPENGL */
  2666 }
  2667 
  2668 SDL_GLContext
  2669 SDL_GL_CreateContext(SDL_Window * window)
  2670 {
  2671     SDL_GLContext ctx = NULL;
  2672     CHECK_WINDOW_MAGIC(window, NULL);
  2673 
  2674     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2675         SDL_SetError("The specified window isn't an OpenGL window");
  2676         return NULL;
  2677     }
  2678 
  2679     ctx = _this->GL_CreateContext(_this, window);
  2680 
  2681     /* Creating a context is assumed to make it current in the SDL driver. */
  2682     _this->current_glwin = window;
  2683     _this->current_glctx = ctx;
  2684 
  2685     return ctx;
  2686 }
  2687 
  2688 int
  2689 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2690 {
  2691     int retval;
  2692 
  2693     CHECK_WINDOW_MAGIC(window, -1);
  2694 
  2695     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2696         return SDL_SetError("The specified window isn't an OpenGL window");
  2697     }
  2698     if (!ctx) {
  2699         window = NULL;
  2700     }
  2701 
  2702     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
  2703         retval = 0;  /* we're already current. */
  2704     } else {
  2705         retval = _this->GL_MakeCurrent(_this, window, ctx);
  2706         if (retval == 0) {
  2707             _this->current_glwin = window;
  2708             _this->current_glctx = ctx;
  2709         }
  2710     }
  2711 
  2712     return retval;
  2713 }
  2714 
  2715 int
  2716 SDL_GL_SetSwapInterval(int interval)
  2717 {
  2718     if (!_this) {
  2719         return SDL_UninitializedVideo();
  2720     } else if (_this->current_glctx == NULL) {
  2721         return SDL_SetError("No OpenGL context has been made current");
  2722     } else if (_this->GL_SetSwapInterval) {
  2723         return _this->GL_SetSwapInterval(_this, interval);
  2724     } else {
  2725         return SDL_SetError("Setting the swap interval is not supported");
  2726     }
  2727 }
  2728 
  2729 int
  2730 SDL_GL_GetSwapInterval(void)
  2731 {
  2732     if (!_this) {
  2733         return 0;
  2734     } else if (_this->current_glctx == NULL) {
  2735         return 0;
  2736     } else if (_this->GL_GetSwapInterval) {
  2737         return _this->GL_GetSwapInterval(_this);
  2738     } else {
  2739         return 0;
  2740     }
  2741 }
  2742 
  2743 void
  2744 SDL_GL_SwapWindow(SDL_Window * window)
  2745 {
  2746     CHECK_WINDOW_MAGIC(window, );
  2747 
  2748     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2749         SDL_SetError("The specified window isn't an OpenGL window");
  2750         return;
  2751     }
  2752     _this->GL_SwapWindow(_this, window);
  2753 }
  2754 
  2755 void
  2756 SDL_GL_DeleteContext(SDL_GLContext context)
  2757 {
  2758     if (!_this || !context) {
  2759         return;
  2760     }
  2761     _this->GL_MakeCurrent(_this, NULL, NULL);
  2762     _this->GL_DeleteContext(_this, context);
  2763 }
  2764 
  2765 #if 0                           // FIXME
  2766 /*
  2767  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2768  * & 2 for alpha channel.
  2769  */
  2770 static void
  2771 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2772 {
  2773     int x, y;
  2774     Uint32 colorkey;
  2775 #define SET_MASKBIT(icon, x, y, mask) \
  2776 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2777 
  2778     colorkey = icon->format->colorkey;
  2779     switch (icon->format->BytesPerPixel) {
  2780     case 1:
  2781         {
  2782             Uint8 *pixels;
  2783             for (y = 0; y < icon->h; ++y) {
  2784                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2785                 for (x = 0; x < icon->w; ++x) {
  2786                     if (*pixels++ == colorkey) {
  2787                         SET_MASKBIT(icon, x, y, mask);
  2788                     }
  2789                 }
  2790             }
  2791         }
  2792         break;
  2793 
  2794     case 2:
  2795         {
  2796             Uint16 *pixels;
  2797             for (y = 0; y < icon->h; ++y) {
  2798                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2799                 for (x = 0; x < icon->w; ++x) {
  2800                     if ((flags & 1) && *pixels == colorkey) {
  2801                         SET_MASKBIT(icon, x, y, mask);
  2802                     } else if ((flags & 2)
  2803                                && (*pixels & icon->format->Amask) == 0) {
  2804                         SET_MASKBIT(icon, x, y, mask);
  2805                     }
  2806                     pixels++;
  2807                 }
  2808             }
  2809         }
  2810         break;
  2811 
  2812     case 4:
  2813         {
  2814             Uint32 *pixels;
  2815             for (y = 0; y < icon->h; ++y) {
  2816                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2817                 for (x = 0; x < icon->w; ++x) {
  2818                     if ((flags & 1) && *pixels == colorkey) {
  2819                         SET_MASKBIT(icon, x, y, mask);
  2820                     } else if ((flags & 2)
  2821                                && (*pixels & icon->format->Amask) == 0) {
  2822                         SET_MASKBIT(icon, x, y, mask);
  2823                     }
  2824                     pixels++;
  2825                 }
  2826             }
  2827         }
  2828         break;
  2829     }
  2830 }
  2831 
  2832 /*
  2833  * Sets the window manager icon for the display window.
  2834  */
  2835 void
  2836 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2837 {
  2838     if (icon && _this->SetIcon) {
  2839         /* Generate a mask if necessary, and create the icon! */
  2840         if (mask == NULL) {
  2841             int mask_len = icon->h * (icon->w + 7) / 8;
  2842             int flags = 0;
  2843             mask = (Uint8 *) SDL_malloc(mask_len);
  2844             if (mask == NULL) {
  2845                 return;
  2846             }
  2847             SDL_memset(mask, ~0, mask_len);
  2848             if (icon->flags & SDL_SRCCOLORKEY)
  2849                 flags |= 1;
  2850             if (icon->flags & SDL_SRCALPHA)
  2851                 flags |= 2;
  2852             if (flags) {
  2853                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2854             }
  2855             _this->SetIcon(_this, icon, mask);
  2856             SDL_free(mask);
  2857         } else {
  2858             _this->SetIcon(_this, icon, mask);
  2859         }
  2860     }
  2861 }
  2862 #endif
  2863 
  2864 SDL_bool
  2865 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2866 {
  2867     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2868 
  2869     if (!info) {
  2870         return SDL_FALSE;
  2871     }
  2872     info->subsystem = SDL_SYSWM_UNKNOWN;
  2873 
  2874     if (!_this->GetWindowWMInfo) {
  2875         return SDL_FALSE;
  2876     }
  2877     return (_this->GetWindowWMInfo(_this, window, info));
  2878 }
  2879 
  2880 void
  2881 SDL_StartTextInput(void)
  2882 {
  2883     SDL_Window *window;
  2884 
  2885     /* First, enable text events */
  2886     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2887     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2888 
  2889     /* Then show the on-screen keyboard, if any */
  2890     window = SDL_GetFocusWindow();
  2891     if (window && _this && _this->SDL_ShowScreenKeyboard) {
  2892         _this->SDL_ShowScreenKeyboard(_this, window);
  2893     }
  2894 
  2895     /* Finally start the text input system */
  2896     if (_this && _this->StartTextInput) {
  2897         _this->StartTextInput(_this);
  2898     }
  2899 }
  2900 
  2901 SDL_bool
  2902 SDL_IsTextInputActive(void)
  2903 {
  2904     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  2905 }
  2906 
  2907 void
  2908 SDL_StopTextInput(void)
  2909 {
  2910     SDL_Window *window;
  2911 
  2912     /* Stop the text input system */
  2913     if (_this && _this->StopTextInput) {
  2914         _this->StopTextInput(_this);
  2915     }
  2916 
  2917     /* Hide the on-screen keyboard, if any */
  2918     window = SDL_GetFocusWindow();
  2919     if (window && _this && _this->SDL_HideScreenKeyboard) {
  2920         _this->SDL_HideScreenKeyboard(_this, window);
  2921     }
  2922 
  2923     /* Finally disable text events */
  2924     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2925     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2926 }
  2927 
  2928 void
  2929 SDL_SetTextInputRect(SDL_Rect *rect)
  2930 {
  2931     if (_this && _this->SetTextInputRect) {
  2932         _this->SetTextInputRect(_this, rect);
  2933     }
  2934 }
  2935 
  2936 SDL_bool
  2937 SDL_HasScreenKeyboardSupport(void)
  2938 {
  2939     if (_this && _this->SDL_HasScreenKeyboardSupport) {
  2940         return _this->SDL_HasScreenKeyboardSupport(_this);
  2941     }
  2942     return SDL_FALSE;
  2943 }
  2944 
  2945 SDL_bool
  2946 SDL_IsScreenKeyboardShown(SDL_Window *window)
  2947 {
  2948     if (window && _this && _this->SDL_IsScreenKeyboardShown) {
  2949         return _this->SDL_IsScreenKeyboardShown(_this, window);
  2950     }
  2951     return SDL_FALSE;
  2952 }
  2953 
  2954 #if SDL_VIDEO_DRIVER_WINDOWS
  2955 #include "windows/SDL_windowsmessagebox.h"
  2956 #endif
  2957 #if SDL_VIDEO_DRIVER_COCOA
  2958 #include "cocoa/SDL_cocoamessagebox.h"
  2959 #endif
  2960 #if SDL_VIDEO_DRIVER_UIKIT
  2961 #include "uikit/SDL_uikitmessagebox.h"
  2962 #endif
  2963 #if SDL_VIDEO_DRIVER_X11
  2964 #include "x11/SDL_x11messagebox.h"
  2965 #endif
  2966 
  2967 int
  2968 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  2969 {
  2970     int dummybutton;
  2971 	int retval = -1;
  2972 	SDL_bool relative_mode = SDL_GetRelativeMouseMode();
  2973 	int show_cursor_prev = SDL_ShowCursor( 1 );
  2974 
  2975 	SDL_SetRelativeMouseMode( SDL_FALSE );
  2976 
  2977     if (!buttonid) {
  2978         buttonid = &dummybutton;
  2979     }
  2980     if (_this && _this->ShowMessageBox) {
  2981         if (_this->ShowMessageBox(_this, messageboxdata, buttonid) == 0) {
  2982 			retval = 0;
  2983         }
  2984     }
  2985 
  2986     /* It's completely fine to call this function before video is initialized */
  2987 #if SDL_VIDEO_DRIVER_WINDOWS
  2988     if ((retval == -1) && (WIN_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  2989         retval = 0;
  2990     }
  2991 #endif
  2992 #if SDL_VIDEO_DRIVER_COCOA
  2993     if ((retval == -1) && (Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  2994         retval = 0;
  2995     }
  2996 #endif
  2997 #if SDL_VIDEO_DRIVER_UIKIT
  2998     if ((retval == -1) && (UIKit_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  2999         retval = 0;
  3000     }
  3001 #endif
  3002 #if SDL_VIDEO_DRIVER_X11
  3003     if ((retval == -1) && (X11_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3004         retval = 0;
  3005     }
  3006 #endif
  3007 
  3008 	SDL_ShowCursor( show_cursor_prev );
  3009 	SDL_SetRelativeMouseMode( relative_mode );
  3010 
  3011 	if(retval == -1) {
  3012 		SDL_SetError("No message system available");
  3013 	}
  3014     return retval;
  3015 }
  3016 
  3017 int
  3018 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3019 {
  3020     SDL_MessageBoxData data;
  3021     SDL_MessageBoxButtonData button;
  3022 
  3023     SDL_zero(data);
  3024     data.flags = flags;
  3025     data.title = title;
  3026     data.message = message;
  3027     data.numbuttons = 1;
  3028     data.buttons = &button;
  3029     data.window = window;
  3030 
  3031     SDL_zero(button);
  3032     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3033     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3034     button.text = "OK";
  3035 
  3036     return SDL_ShowMessageBox(&data, NULL);
  3037 }
  3038 
  3039 SDL_bool
  3040 SDL_ShouldAllowTopmost()
  3041 {
  3042 	const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3043 	if (hint) {
  3044 		if (*hint == '0') {
  3045 			return SDL_FALSE;
  3046 		} else {
  3047 			return SDL_TRUE;
  3048 		}
  3049 	}
  3050 	return SDL_TRUE;
  3051 }
  3052 
  3053 /* vi: set ts=4 sw=4 expandtab: */