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