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