src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 15 Dec 2012 00:30:17 +0000
changeset 6755 af77e1a6faf0
parent 6681 5a0396a933b5
child 6775 ca20a61fe03b
child 8377 3a7e8110201e
permissions -rw-r--r--
Improvements from Alfred:
- Add new SDL_WINDOW_FULLSCREEN_DESKTOP video mode, makes a fullscreen window the size of the desktop (i.e no window manager mode change)
- Fix crash in warp mouse if you specified null as the window
- Added new SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS Hint, if set to 0 then don't minimize a fullscreen window on focus lost (if not set or set to non-zero then minimize on focus loss)
     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     } else {
   585         SDL_OutOfMemory();
   586     }
   587     return index;
   588 }
   589 
   590 int
   591 SDL_GetNumVideoDisplays(void)
   592 {
   593     if (!_this) {
   594         SDL_UninitializedVideo();
   595         return 0;
   596     }
   597     return _this->num_displays;
   598 }
   599 
   600 static int
   601 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   602 {
   603     int displayIndex;
   604 
   605     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   606         if (display == &_this->displays[displayIndex]) {
   607             return displayIndex;
   608         }
   609     }
   610 
   611     /* Couldn't find the display, just use index 0 */
   612     return 0;
   613 }
   614 
   615 int
   616 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   617 {
   618     CHECK_DISPLAY_INDEX(displayIndex, -1);
   619 
   620     if (rect) {
   621         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   622 
   623         if (_this->GetDisplayBounds) {
   624             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   625                 return 0;
   626             }
   627         }
   628 
   629         /* Assume that the displays are left to right */
   630         if (displayIndex == 0) {
   631             rect->x = 0;
   632             rect->y = 0;
   633         } else {
   634             SDL_GetDisplayBounds(displayIndex-1, rect);
   635             rect->x += rect->w;
   636         }
   637         rect->w = display->current_mode.w;
   638         rect->h = display->current_mode.h;
   639     }
   640     return 0;
   641 }
   642 
   643 SDL_bool
   644 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   645 {
   646     SDL_DisplayMode *modes;
   647     int i, nmodes;
   648 
   649     /* Make sure we don't already have the mode in the list */
   650     modes = display->display_modes;
   651     nmodes = display->num_display_modes;
   652     for (i = nmodes; i--;) {
   653         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   654             return SDL_FALSE;
   655         }
   656     }
   657 
   658     /* Go ahead and add the new mode */
   659     if (nmodes == display->max_display_modes) {
   660         modes =
   661             SDL_realloc(modes,
   662                         (display->max_display_modes + 32) * sizeof(*modes));
   663         if (!modes) {
   664             return SDL_FALSE;
   665         }
   666         display->display_modes = modes;
   667         display->max_display_modes += 32;
   668     }
   669     modes[nmodes] = *mode;
   670     display->num_display_modes++;
   671 
   672     /* Re-sort video modes */
   673     SDL_qsort(display->display_modes, display->num_display_modes,
   674               sizeof(SDL_DisplayMode), cmpmodes);
   675 
   676     return SDL_TRUE;
   677 }
   678 
   679 static int
   680 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   681 {
   682     if (!display->num_display_modes && _this->GetDisplayModes) {
   683         _this->GetDisplayModes(_this, display);
   684         SDL_qsort(display->display_modes, display->num_display_modes,
   685                   sizeof(SDL_DisplayMode), cmpmodes);
   686     }
   687     return display->num_display_modes;
   688 }
   689 
   690 int
   691 SDL_GetNumDisplayModes(int displayIndex)
   692 {
   693     CHECK_DISPLAY_INDEX(displayIndex, -1);
   694 
   695     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   696 }
   697 
   698 int
   699 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   700 {
   701     SDL_VideoDisplay *display;
   702 
   703     CHECK_DISPLAY_INDEX(displayIndex, -1);
   704 
   705     display = &_this->displays[displayIndex];
   706     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   707         SDL_SetError("index must be in the range of 0 - %d",
   708                      SDL_GetNumDisplayModesForDisplay(display) - 1);
   709         return -1;
   710     }
   711     if (mode) {
   712         *mode = display->display_modes[index];
   713     }
   714     return 0;
   715 }
   716 
   717 int
   718 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   719 {
   720     SDL_VideoDisplay *display;
   721 
   722     CHECK_DISPLAY_INDEX(displayIndex, -1);
   723 
   724     display = &_this->displays[displayIndex];
   725     if (mode) {
   726         *mode = display->desktop_mode;
   727     }
   728     return 0;
   729 }
   730 
   731 int
   732 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   733 {
   734     SDL_VideoDisplay *display;
   735 
   736     CHECK_DISPLAY_INDEX(displayIndex, -1);
   737 
   738     display = &_this->displays[displayIndex];
   739     if (mode) {
   740         *mode = display->current_mode;
   741     }
   742     return 0;
   743 }
   744 
   745 static SDL_DisplayMode *
   746 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   747                                     const SDL_DisplayMode * mode,
   748                                     SDL_DisplayMode * closest)
   749 {
   750     Uint32 target_format;
   751     int target_refresh_rate;
   752     int i;
   753     SDL_DisplayMode *current, *match;
   754 
   755     if (!mode || !closest) {
   756         SDL_SetError("Missing desired mode or closest mode parameter");
   757         return NULL;
   758     }
   759 
   760     /* Default to the desktop format */
   761     if (mode->format) {
   762         target_format = mode->format;
   763     } else {
   764         target_format = display->desktop_mode.format;
   765     }
   766 
   767     /* Default to the desktop refresh rate */
   768     if (mode->refresh_rate) {
   769         target_refresh_rate = mode->refresh_rate;
   770     } else {
   771         target_refresh_rate = display->desktop_mode.refresh_rate;
   772     }
   773 
   774     match = NULL;
   775     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   776         current = &display->display_modes[i];
   777 
   778         if (current->w && (current->w < mode->w)) {
   779             /* Out of sorted modes large enough here */
   780             break;
   781         }
   782         if (current->h && (current->h < mode->h)) {
   783             if (current->w && (current->w == mode->w)) {
   784                 /* Out of sorted modes large enough here */
   785                 break;
   786             }
   787             /* Wider, but not tall enough, due to a different
   788                aspect ratio. This mode must be skipped, but closer
   789                modes may still follow. */
   790             continue;
   791         }
   792         if (!match || current->w < match->w || current->h < match->h) {
   793             match = current;
   794             continue;
   795         }
   796         if (current->format != match->format) {
   797             /* Sorted highest depth to lowest */
   798             if (current->format == target_format ||
   799                 (SDL_BITSPERPIXEL(current->format) >=
   800                  SDL_BITSPERPIXEL(target_format)
   801                  && SDL_PIXELTYPE(current->format) ==
   802                  SDL_PIXELTYPE(target_format))) {
   803                 match = current;
   804             }
   805             continue;
   806         }
   807         if (current->refresh_rate != match->refresh_rate) {
   808             /* Sorted highest refresh to lowest */
   809             if (current->refresh_rate >= target_refresh_rate) {
   810                 match = current;
   811             }
   812         }
   813     }
   814     if (match) {
   815         if (match->format) {
   816             closest->format = match->format;
   817         } else {
   818             closest->format = mode->format;
   819         }
   820         if (match->w && match->h) {
   821             closest->w = match->w;
   822             closest->h = match->h;
   823         } else {
   824             closest->w = mode->w;
   825             closest->h = mode->h;
   826         }
   827         if (match->refresh_rate) {
   828             closest->refresh_rate = match->refresh_rate;
   829         } else {
   830             closest->refresh_rate = mode->refresh_rate;
   831         }
   832         closest->driverdata = match->driverdata;
   833 
   834         /*
   835          * Pick some reasonable defaults if the app and driver don't
   836          * care
   837          */
   838         if (!closest->format) {
   839             closest->format = SDL_PIXELFORMAT_RGB888;
   840         }
   841         if (!closest->w) {
   842             closest->w = 640;
   843         }
   844         if (!closest->h) {
   845             closest->h = 480;
   846         }
   847         return closest;
   848     }
   849     return NULL;
   850 }
   851 
   852 SDL_DisplayMode *
   853 SDL_GetClosestDisplayMode(int displayIndex,
   854                           const SDL_DisplayMode * mode,
   855                           SDL_DisplayMode * closest)
   856 {
   857     SDL_VideoDisplay *display;
   858 
   859     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   860 
   861     display = &_this->displays[displayIndex];
   862     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   863 }
   864 
   865 static int
   866 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   867 {
   868     SDL_DisplayMode display_mode;
   869     SDL_DisplayMode current_mode;
   870 
   871     if (mode) {
   872         display_mode = *mode;
   873 
   874         /* Default to the current mode */
   875         if (!display_mode.format) {
   876             display_mode.format = display->current_mode.format;
   877         }
   878         if (!display_mode.w) {
   879             display_mode.w = display->current_mode.w;
   880         }
   881         if (!display_mode.h) {
   882             display_mode.h = display->current_mode.h;
   883         }
   884         if (!display_mode.refresh_rate) {
   885             display_mode.refresh_rate = display->current_mode.refresh_rate;
   886         }
   887 
   888         /* Get a good video mode, the closest one possible */
   889         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   890             SDL_SetError("No video mode large enough for %dx%d",
   891                          display_mode.w, display_mode.h);
   892             return -1;
   893         }
   894     } else {
   895         display_mode = display->desktop_mode;
   896     }
   897 
   898     /* See if there's anything left to do */
   899     current_mode = display->current_mode;
   900     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   901         return 0;
   902     }
   903 
   904     /* Actually change the display mode */
   905     if (!_this->SetDisplayMode) {
   906         SDL_SetError("Video driver doesn't support changing display mode");
   907         return -1;
   908     }
   909     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   910         return -1;
   911     }
   912     display->current_mode = display_mode;
   913     return 0;
   914 }
   915 
   916 int
   917 SDL_GetWindowDisplay(SDL_Window * window)
   918 {
   919     int displayIndex;
   920     int i, dist;
   921     int closest = -1;
   922     int closest_dist = 0x7FFFFFFF;
   923     SDL_Point center;
   924     SDL_Point delta;
   925     SDL_Rect rect;
   926 
   927     CHECK_WINDOW_MAGIC(window, -1);
   928 
   929     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   930         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   931         displayIndex = (window->x & 0xFFFF);
   932         if (displayIndex >= _this->num_displays) {
   933             displayIndex = 0;
   934         }
   935         return displayIndex;
   936     }
   937     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   938         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   939         displayIndex = (window->y & 0xFFFF);
   940         if (displayIndex >= _this->num_displays) {
   941             displayIndex = 0;
   942         }
   943         return displayIndex;
   944     }
   945 
   946     /* Find the display containing the window */
   947     for (i = 0; i < _this->num_displays; ++i) {
   948         SDL_VideoDisplay *display = &_this->displays[i];
   949 
   950         if (display->fullscreen_window == window) {
   951             return i;
   952         }
   953     }
   954     center.x = window->x + window->w / 2;
   955     center.y = window->y + window->h / 2;
   956     for (i = 0; i < _this->num_displays; ++i) {
   957         SDL_GetDisplayBounds(i, &rect);
   958         if (SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   959             return i;
   960         }
   961 
   962         delta.x = center.x - (rect.x + rect.w / 2);
   963         delta.y = center.y - (rect.y + rect.h / 2);
   964         dist = (delta.x*delta.x + delta.y*delta.y);
   965         if (dist < closest_dist) {
   966             closest = i;
   967             closest_dist = dist;
   968         }
   969     }
   970     if (closest < 0) {
   971         SDL_SetError("Couldn't find any displays");
   972     }
   973     return closest;
   974 }
   975 
   976 SDL_VideoDisplay *
   977 SDL_GetDisplayForWindow(SDL_Window *window)
   978 {
   979     int displayIndex = SDL_GetWindowDisplay(window);
   980     if (displayIndex >= 0) {
   981         return &_this->displays[displayIndex];
   982     } else {
   983         return NULL;
   984     }
   985 }
   986 
   987 int
   988 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   989 {
   990     CHECK_WINDOW_MAGIC(window, -1);
   991 
   992     if (mode) {
   993         window->fullscreen_mode = *mode;
   994     } else {
   995         SDL_zero(window->fullscreen_mode);
   996     }
   997     return 0;
   998 }
   999 
  1000 int
  1001 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
  1002 {
  1003     SDL_DisplayMode fullscreen_mode;
  1004 	SDL_VideoDisplay *display;
  1005 
  1006     CHECK_WINDOW_MAGIC(window, -1);
  1007 
  1008     fullscreen_mode = window->fullscreen_mode;
  1009     if (!fullscreen_mode.w) {
  1010         fullscreen_mode.w = window->w;
  1011     }
  1012     if (!fullscreen_mode.h) {
  1013         fullscreen_mode.h = window->h;
  1014     }
  1015 	
  1016 	display = SDL_GetDisplayForWindow(window);
  1017 
  1018 	/* if in desktop size mode, just return the size of the desktop */
  1019 	if ( ( window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN_DESKTOP ) 
  1020 	{
  1021 		fullscreen_mode = display->desktop_mode;
  1022 	}
  1023 	else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
  1024                                              &fullscreen_mode,
  1025                                              &fullscreen_mode)) {
  1026         SDL_SetError("Couldn't find display mode match");
  1027         return -1;
  1028     }
  1029 
  1030     if (mode) {
  1031         *mode = fullscreen_mode;
  1032     }
  1033     return 0;
  1034 }
  1035 
  1036 Uint32
  1037 SDL_GetWindowPixelFormat(SDL_Window * window)
  1038 {
  1039     SDL_VideoDisplay *display;
  1040 
  1041     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1042 
  1043     display = SDL_GetDisplayForWindow(window);
  1044     return display->current_mode.format;
  1045 }
  1046 
  1047 static void
  1048 SDL_RestoreMousePosition(SDL_Window *window)
  1049 {
  1050     int x, y;
  1051 
  1052     if (window == SDL_GetMouseFocus()) {
  1053         SDL_GetMouseState(&x, &y);
  1054         SDL_WarpMouseInWindow(window, x, y);
  1055     }
  1056 }
  1057 
  1058 static void
  1059 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1060 {
  1061     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1062     SDL_Window *other;
  1063 
  1064     if (fullscreen) {
  1065         /* Hide any other fullscreen windows */
  1066         if (display->fullscreen_window &&
  1067             display->fullscreen_window != window) {
  1068             SDL_MinimizeWindow(display->fullscreen_window);
  1069         }
  1070     }
  1071 
  1072     /* See if anything needs to be done now */
  1073     if ((display->fullscreen_window == window) == fullscreen) {
  1074         return;
  1075     }
  1076 
  1077     /* See if there are any fullscreen windows */
  1078     for (other = _this->windows; other; other = other->next) {
  1079         SDL_bool setDisplayMode = SDL_FALSE;
  1080 
  1081         if (other == window) {
  1082             setDisplayMode = fullscreen;
  1083         } else if (FULLSCREEN_VISIBLE(other) &&
  1084                    SDL_GetDisplayForWindow(other) == display) {
  1085             setDisplayMode = SDL_TRUE;
  1086         }
  1087 
  1088         if (setDisplayMode) {
  1089             SDL_DisplayMode fullscreen_mode;
  1090 
  1091             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1092                 SDL_bool resized = SDL_TRUE;
  1093 
  1094                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1095                     resized = SDL_FALSE;
  1096                 }
  1097 
  1098 				/* only do the mode change if we want exclusive fullscreen */
  1099 				if ( ( window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) != SDL_WINDOW_FULLSCREEN_DESKTOP ) 
  1100 					SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1101 				else
  1102 					SDL_SetDisplayModeForDisplay(display, NULL);
  1103 
  1104 				
  1105                 if (_this->SetWindowFullscreen) {
  1106                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1107                 }
  1108                 display->fullscreen_window = other;
  1109 
  1110                 /* Generate a mode change event here */
  1111                 if (resized) {
  1112                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1113                                         fullscreen_mode.w, fullscreen_mode.h);
  1114                 } else {
  1115                     SDL_OnWindowResized(other);
  1116                 }
  1117 
  1118                 SDL_RestoreMousePosition(other);
  1119                 return;
  1120             }
  1121         }
  1122     }
  1123 
  1124     /* Nope, restore the desktop mode */
  1125     SDL_SetDisplayModeForDisplay(display, NULL);
  1126 
  1127     if (_this->SetWindowFullscreen) {
  1128         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1129     }
  1130     display->fullscreen_window = NULL;
  1131 
  1132     /* Generate a mode change event here */
  1133     SDL_OnWindowResized(window);
  1134 
  1135     /* Restore the cursor position */
  1136     SDL_RestoreMousePosition(window);
  1137 }
  1138 
  1139 #define CREATE_FLAGS \
  1140     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE)
  1141 
  1142 static void
  1143 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1144 {
  1145     window->windowed.x = window->x;
  1146     window->windowed.y = window->y;
  1147     window->windowed.w = window->w;
  1148     window->windowed.h = window->h;
  1149 
  1150     if (flags & SDL_WINDOW_MAXIMIZED) {
  1151         SDL_MaximizeWindow(window);
  1152     }
  1153     if (flags & SDL_WINDOW_MINIMIZED) {
  1154         SDL_MinimizeWindow(window);
  1155     }
  1156     if (flags & SDL_WINDOW_FULLSCREEN) {
  1157         SDL_SetWindowFullscreen(window, flags);
  1158     }
  1159     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1160         SDL_SetWindowGrab(window, SDL_TRUE);
  1161     }
  1162     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1163         SDL_ShowWindow(window);
  1164     }
  1165 }
  1166 
  1167 SDL_Window *
  1168 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1169 {
  1170     SDL_Window *window;
  1171 
  1172     if (!_this) {
  1173         /* Initialize the video system if needed */
  1174         if (SDL_VideoInit(NULL) < 0) {
  1175             return NULL;
  1176         }
  1177     }
  1178 
  1179     /* Some platforms can't create zero-sized windows */
  1180     if (w < 1) {
  1181         w = 1;
  1182     }
  1183     if (h < 1) {
  1184         h = 1;
  1185     }
  1186 
  1187     /* Some platforms have OpenGL enabled by default */
  1188 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__
  1189     flags |= SDL_WINDOW_OPENGL;
  1190 #endif
  1191     if (flags & SDL_WINDOW_OPENGL) {
  1192         if (!_this->GL_CreateContext) {
  1193             SDL_SetError("No OpenGL support in video driver");
  1194             return NULL;
  1195         }
  1196         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1197             return NULL;
  1198         }
  1199     }
  1200     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1201     window->magic = &_this->window_magic;
  1202     window->id = _this->next_object_id++;
  1203     window->x = x;
  1204     window->y = y;
  1205     window->w = w;
  1206     window->h = h;
  1207     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1208         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1209         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1210         int displayIndex;
  1211         SDL_Rect bounds;
  1212 
  1213         displayIndex = SDL_GetIndexOfDisplay(display);
  1214         SDL_GetDisplayBounds(displayIndex, &bounds);
  1215         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1216             window->x = bounds.x + (bounds.w - w) / 2;
  1217         }
  1218         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1219             window->y = bounds.y + (bounds.h - h) / 2;
  1220         }
  1221     }
  1222     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1223     window->brightness = 1.0f;
  1224     window->next = _this->windows;
  1225     if (_this->windows) {
  1226         _this->windows->prev = window;
  1227     }
  1228     _this->windows = window;
  1229 
  1230     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1231         SDL_DestroyWindow(window);
  1232         return NULL;
  1233     }
  1234 
  1235     if (title) {
  1236         SDL_SetWindowTitle(window, title);
  1237     }
  1238     SDL_FinishWindowCreation(window, flags);
  1239     
  1240     /* If the window was created fullscreen, make sure the mode code matches */
  1241     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1242 
  1243     return window;
  1244 }
  1245 
  1246 SDL_Window *
  1247 SDL_CreateWindowFrom(const void *data)
  1248 {
  1249     SDL_Window *window;
  1250 
  1251     if (!_this) {
  1252         SDL_UninitializedVideo();
  1253         return NULL;
  1254     }
  1255     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1256     window->magic = &_this->window_magic;
  1257     window->id = _this->next_object_id++;
  1258     window->flags = SDL_WINDOW_FOREIGN;
  1259     window->brightness = 1.0f;
  1260     window->next = _this->windows;
  1261     if (_this->windows) {
  1262         _this->windows->prev = window;
  1263     }
  1264     _this->windows = window;
  1265 
  1266     if (!_this->CreateWindowFrom ||
  1267         _this->CreateWindowFrom(_this, window, data) < 0) {
  1268         SDL_DestroyWindow(window);
  1269         return NULL;
  1270     }
  1271     return window;
  1272 }
  1273 
  1274 int
  1275 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1276 {
  1277     char *title = window->title;
  1278 
  1279     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1280         SDL_SetError("No OpenGL support in video driver");
  1281         return -1;
  1282     }
  1283 
  1284     if (window->flags & SDL_WINDOW_FOREIGN) {
  1285         /* Can't destroy and re-create foreign windows, hrm */
  1286         flags |= SDL_WINDOW_FOREIGN;
  1287     } else {
  1288         flags &= ~SDL_WINDOW_FOREIGN;
  1289     }
  1290 
  1291     /* Restore video mode, etc. */
  1292     SDL_HideWindow(window);
  1293 
  1294     /* Tear down the old native window */
  1295     if (window->surface) {
  1296         window->surface->flags &= ~SDL_DONTFREE;
  1297         SDL_FreeSurface(window->surface);
  1298     }
  1299     if (_this->DestroyWindowFramebuffer) {
  1300         _this->DestroyWindowFramebuffer(_this, window);
  1301     }
  1302     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1303         _this->DestroyWindow(_this, window);
  1304     }
  1305 
  1306     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1307         if (flags & SDL_WINDOW_OPENGL) {
  1308             SDL_GL_LoadLibrary(NULL);
  1309         } else {
  1310             SDL_GL_UnloadLibrary();
  1311         }
  1312     }
  1313 
  1314     window->title = NULL;
  1315     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1316 
  1317     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1318         if (_this->CreateWindow(_this, window) < 0) {
  1319             if (flags & SDL_WINDOW_OPENGL) {
  1320                 SDL_GL_UnloadLibrary();
  1321             }
  1322             return -1;
  1323         }
  1324     }
  1325 
  1326     if (title) {
  1327         SDL_SetWindowTitle(window, title);
  1328         SDL_free(title);
  1329     }
  1330     SDL_FinishWindowCreation(window, flags);
  1331 
  1332     return 0;
  1333 }
  1334 
  1335 Uint32
  1336 SDL_GetWindowID(SDL_Window * window)
  1337 {
  1338     CHECK_WINDOW_MAGIC(window, 0);
  1339 
  1340     return window->id;
  1341 }
  1342 
  1343 SDL_Window *
  1344 SDL_GetWindowFromID(Uint32 id)
  1345 {
  1346     SDL_Window *window;
  1347 
  1348     if (!_this) {
  1349         return NULL;
  1350     }
  1351     for (window = _this->windows; window; window = window->next) {
  1352         if (window->id == id) {
  1353             return window;
  1354         }
  1355     }
  1356     return NULL;
  1357 }
  1358 
  1359 Uint32
  1360 SDL_GetWindowFlags(SDL_Window * window)
  1361 {
  1362     CHECK_WINDOW_MAGIC(window, 0);
  1363 
  1364     return window->flags;
  1365 }
  1366 
  1367 void
  1368 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1369 {
  1370     CHECK_WINDOW_MAGIC(window, );
  1371 
  1372     if (title == window->title) {
  1373         return;
  1374     }
  1375     if (window->title) {
  1376         SDL_free(window->title);
  1377     }
  1378     if (title && *title) {
  1379         window->title = SDL_strdup(title);
  1380     } else {
  1381         window->title = NULL;
  1382     }
  1383 
  1384     if (_this->SetWindowTitle) {
  1385         _this->SetWindowTitle(_this, window);
  1386     }
  1387 }
  1388 
  1389 const char *
  1390 SDL_GetWindowTitle(SDL_Window * window)
  1391 {
  1392     CHECK_WINDOW_MAGIC(window, "");
  1393 
  1394     return window->title ? window->title : "";
  1395 }
  1396 
  1397 void
  1398 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1399 {
  1400     CHECK_WINDOW_MAGIC(window, );
  1401 
  1402     if (!icon) {
  1403         return;
  1404     }
  1405 
  1406     if (_this->SetWindowIcon) {
  1407         _this->SetWindowIcon(_this, window, icon);
  1408     }
  1409 }
  1410 
  1411 void*
  1412 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1413 {
  1414     SDL_WindowUserData *prev, *data;
  1415 
  1416     CHECK_WINDOW_MAGIC(window, NULL);
  1417 
  1418     /* See if the named data already exists */
  1419     prev = NULL;
  1420     for (data = window->data; data; prev = data, data = data->next) {
  1421         if (SDL_strcmp(data->name, name) == 0) {
  1422             void *last_value = data->data;
  1423 
  1424             if (userdata) {
  1425                 /* Set the new value */
  1426                 data->data = userdata;
  1427             } else {
  1428                 /* Delete this value */
  1429                 if (prev) {
  1430                     prev->next = data->next;
  1431                 } else {
  1432                     window->data = data->next;
  1433                 }
  1434                 SDL_free(data->name);
  1435                 SDL_free(data);
  1436             }
  1437             return last_value;
  1438         }
  1439     }
  1440 
  1441     /* Add new data to the window */
  1442     if (userdata) {
  1443         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1444         data->name = SDL_strdup(name);
  1445         data->data = userdata;
  1446         data->next = window->data;
  1447         window->data = data;
  1448     }
  1449     return NULL;
  1450 }
  1451 
  1452 void *
  1453 SDL_GetWindowData(SDL_Window * window, const char *name)
  1454 {
  1455     SDL_WindowUserData *data;
  1456 
  1457     CHECK_WINDOW_MAGIC(window, NULL);
  1458 
  1459     for (data = window->data; data; data = data->next) {
  1460         if (SDL_strcmp(data->name, name) == 0) {
  1461             return data->data;
  1462         }
  1463     }
  1464     return NULL;
  1465 }
  1466 
  1467 void
  1468 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1469 {
  1470     CHECK_WINDOW_MAGIC(window, );
  1471 
  1472     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1473         window->x = x;
  1474     }
  1475     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1476         window->y = y;
  1477     }
  1478     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1479         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1480         int displayIndex;
  1481         SDL_Rect bounds;
  1482 
  1483         displayIndex = SDL_GetIndexOfDisplay(display);
  1484         SDL_GetDisplayBounds(displayIndex, &bounds);
  1485         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1486             window->x = bounds.x + (bounds.w - window->w) / 2;
  1487         }
  1488         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1489             window->y = bounds.y + (bounds.h - window->h) / 2;
  1490         }
  1491     }
  1492     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1493         if (_this->SetWindowPosition) {
  1494             _this->SetWindowPosition(_this, window);
  1495         }
  1496         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1497     }
  1498 }
  1499 
  1500 void
  1501 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1502 {
  1503     /* Clear the values */
  1504     if (x) {
  1505         *x = 0;
  1506     }
  1507     if (y) {
  1508         *y = 0;
  1509     }
  1510 
  1511     CHECK_WINDOW_MAGIC(window, );
  1512 
  1513     /* Fullscreen windows are always at their display's origin */
  1514     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1515     } else {
  1516         if (x) {
  1517             *x = window->x;
  1518         }
  1519         if (y) {
  1520             *y = window->y;
  1521         }
  1522     }
  1523 }
  1524 
  1525 void
  1526 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1527 {
  1528     CHECK_WINDOW_MAGIC(window, );
  1529     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1530         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1531         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1532         if ((want != have) && (_this->SetWindowBordered)) {
  1533             if (want) {
  1534                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1535             } else {
  1536                 window->flags |= SDL_WINDOW_BORDERLESS;
  1537             }
  1538             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1539         }
  1540     }
  1541 }
  1542 
  1543 void
  1544 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1545 {
  1546     CHECK_WINDOW_MAGIC(window, );
  1547 
  1548     /* FIXME: Should this change fullscreen modes? */
  1549     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1550         window->w = w;
  1551         window->h = h;
  1552         if (_this->SetWindowSize) {
  1553             _this->SetWindowSize(_this, window);
  1554         }
  1555         if (window->w == w && window->h == h) {
  1556             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1557             SDL_OnWindowResized(window);
  1558         }
  1559     }
  1560 }
  1561 
  1562 void
  1563 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1564 {
  1565     int dummy;
  1566 
  1567     if (!w) {
  1568         w = &dummy;
  1569     }
  1570     if (!h) {
  1571         h = &dummy;
  1572     }
  1573 
  1574     *w = 0;
  1575     *h = 0;
  1576 
  1577     CHECK_WINDOW_MAGIC(window, );
  1578 
  1579     if (_this && window && window->magic == &_this->window_magic) {
  1580         *w = window->w;
  1581         *h = window->h;
  1582     }
  1583 }
  1584 
  1585 void
  1586 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1587 {
  1588     CHECK_WINDOW_MAGIC(window, );
  1589     
  1590     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1591         window->min_w = min_w;
  1592         window->min_h = min_h;
  1593         if (_this->SetWindowMinimumSize) {
  1594             _this->SetWindowMinimumSize(_this, window);
  1595         }
  1596         /* Ensure that window is not smaller than minimal size */
  1597         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1598     }
  1599 }
  1600 
  1601 void
  1602 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1603 {
  1604     int dummy;
  1605     
  1606     if (!min_w) {
  1607         min_w = &dummy;
  1608     }
  1609     if (!min_h) {
  1610         min_h = &dummy;
  1611     }
  1612     
  1613     *min_w = 0;
  1614     *min_h = 0;
  1615     
  1616     CHECK_WINDOW_MAGIC(window, );
  1617     
  1618     if (_this && window && window->magic == &_this->window_magic) {
  1619         *min_w = window->min_w;
  1620         *min_h = window->min_h;
  1621     }
  1622 }
  1623 
  1624 void
  1625 SDL_ShowWindow(SDL_Window * window)
  1626 {
  1627     CHECK_WINDOW_MAGIC(window, );
  1628 
  1629     if (window->flags & SDL_WINDOW_SHOWN) {
  1630         return;
  1631     }
  1632 
  1633     if (_this->ShowWindow) {
  1634         _this->ShowWindow(_this, window);
  1635     }
  1636     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1637 }
  1638 
  1639 void
  1640 SDL_HideWindow(SDL_Window * window)
  1641 {
  1642     CHECK_WINDOW_MAGIC(window, );
  1643 
  1644     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1645         return;
  1646     }
  1647 
  1648     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1649 
  1650     if (_this->HideWindow) {
  1651         _this->HideWindow(_this, window);
  1652     }
  1653     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1654 }
  1655 
  1656 void
  1657 SDL_RaiseWindow(SDL_Window * window)
  1658 {
  1659     CHECK_WINDOW_MAGIC(window, );
  1660 
  1661     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1662         return;
  1663     }
  1664     if (_this->RaiseWindow) {
  1665         _this->RaiseWindow(_this, window);
  1666     }
  1667 }
  1668 
  1669 void
  1670 SDL_MaximizeWindow(SDL_Window * window)
  1671 {
  1672     CHECK_WINDOW_MAGIC(window, );
  1673 
  1674     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1675         return;
  1676     }
  1677 
  1678     if (_this->MaximizeWindow) {
  1679         _this->MaximizeWindow(_this, window);
  1680     }
  1681 }
  1682 
  1683 void
  1684 SDL_MinimizeWindow(SDL_Window * window)
  1685 {
  1686     CHECK_WINDOW_MAGIC(window, );
  1687 
  1688     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1689         return;
  1690     }
  1691 
  1692     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1693 
  1694     if (_this->MinimizeWindow) {
  1695         _this->MinimizeWindow(_this, window);
  1696     }
  1697 }
  1698 
  1699 void
  1700 SDL_RestoreWindow(SDL_Window * window)
  1701 {
  1702     CHECK_WINDOW_MAGIC(window, );
  1703 
  1704     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1705         return;
  1706     }
  1707 
  1708     if (_this->RestoreWindow) {
  1709         _this->RestoreWindow(_this, window);
  1710     }
  1711 }
  1712 
  1713 #define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN )
  1714 int
  1715 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1716 {
  1717     CHECK_WINDOW_MAGIC(window, -1);
  1718 
  1719 	flags &= FULLSCREEN_MASK;
  1720 	
  1721     if ( flags == (window->flags & FULLSCREEN_MASK) ) {
  1722         return 0;
  1723     }
  1724 	
  1725 	/* clear the previous flags and OR in the new ones */
  1726 	window->flags &= ~FULLSCREEN_MASK;
  1727     window->flags |= flags;
  1728 
  1729     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1730 
  1731     return 0;
  1732 }
  1733 
  1734 static SDL_Surface *
  1735 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1736 {
  1737     Uint32 format;
  1738     void *pixels;
  1739     int pitch;
  1740     int bpp;
  1741     Uint32 Rmask, Gmask, Bmask, Amask;
  1742 
  1743     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1744         return NULL;
  1745     }
  1746 
  1747     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1748         return NULL;
  1749     }
  1750 
  1751     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1752         return NULL;
  1753     }
  1754 
  1755     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1756 }
  1757 
  1758 SDL_Surface *
  1759 SDL_GetWindowSurface(SDL_Window * window)
  1760 {
  1761     CHECK_WINDOW_MAGIC(window, NULL);
  1762 
  1763     if (!window->surface_valid) {
  1764         if (window->surface) {
  1765             window->surface->flags &= ~SDL_DONTFREE;
  1766             SDL_FreeSurface(window->surface);
  1767         }
  1768         window->surface = SDL_CreateWindowFramebuffer(window);
  1769         if (window->surface) {
  1770             window->surface_valid = SDL_TRUE;
  1771             window->surface->flags |= SDL_DONTFREE;
  1772         }
  1773     }
  1774     return window->surface;
  1775 }
  1776 
  1777 int
  1778 SDL_UpdateWindowSurface(SDL_Window * window)
  1779 {
  1780     SDL_Rect full_rect;
  1781 
  1782     CHECK_WINDOW_MAGIC(window, -1);
  1783 
  1784     full_rect.x = 0;
  1785     full_rect.y = 0;
  1786     full_rect.w = window->w;
  1787     full_rect.h = window->h;
  1788     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1789 }
  1790 
  1791 int
  1792 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
  1793                              int numrects)
  1794 {
  1795     CHECK_WINDOW_MAGIC(window, -1);
  1796 
  1797     if (!window->surface_valid) {
  1798         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1799         return -1;
  1800     }
  1801 
  1802     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1803 }
  1804 
  1805 int
  1806 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1807 {
  1808     Uint16 ramp[256];
  1809     int status;
  1810 
  1811     CHECK_WINDOW_MAGIC(window, -1);
  1812 
  1813     SDL_CalculateGammaRamp(brightness, ramp);
  1814     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1815     if (status == 0) {
  1816         window->brightness = brightness;
  1817     }
  1818     return status;
  1819 }
  1820 
  1821 float
  1822 SDL_GetWindowBrightness(SDL_Window * window)
  1823 {
  1824     CHECK_WINDOW_MAGIC(window, 1.0f);
  1825 
  1826     return window->brightness;
  1827 }
  1828 
  1829 int
  1830 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1831                                             const Uint16 * green,
  1832                                             const Uint16 * blue)
  1833 {
  1834     CHECK_WINDOW_MAGIC(window, -1);
  1835 
  1836     if (!_this->SetWindowGammaRamp) {
  1837         SDL_Unsupported();
  1838         return -1;
  1839     }
  1840 
  1841     if (!window->gamma) {
  1842         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1843             return -1;
  1844         }
  1845     }
  1846 
  1847     if (red) {
  1848         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1849     }
  1850     if (green) {
  1851         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1852     }
  1853     if (blue) {
  1854         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1855     }
  1856     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1857         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1858     } else {
  1859         return 0;
  1860     }
  1861 }
  1862 
  1863 int
  1864 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  1865                                             Uint16 * green,
  1866                                             Uint16 * blue)
  1867 {
  1868     CHECK_WINDOW_MAGIC(window, -1);
  1869 
  1870     if (!window->gamma) {
  1871         int i;
  1872 
  1873         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  1874         if (!window->gamma) {
  1875             SDL_OutOfMemory();
  1876             return -1;
  1877         }
  1878         window->saved_gamma = window->gamma + 3*256;
  1879 
  1880         if (_this->GetWindowGammaRamp) {
  1881             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  1882                 return -1;
  1883             }
  1884         } else {
  1885             /* Create an identity gamma ramp */
  1886             for (i = 0; i < 256; ++i) {
  1887                 Uint16 value = (Uint16)((i << 8) | i);
  1888 
  1889                 window->gamma[0*256+i] = value;
  1890                 window->gamma[1*256+i] = value;
  1891                 window->gamma[2*256+i] = value;
  1892             }
  1893         }
  1894         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  1895     }
  1896 
  1897     if (red) {
  1898         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  1899     }
  1900     if (green) {
  1901         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  1902     }
  1903     if (blue) {
  1904         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  1905     }
  1906     return 0;
  1907 }
  1908 
  1909 void
  1910 SDL_UpdateWindowGrab(SDL_Window * window)
  1911 {
  1912     if (_this->SetWindowGrab) {
  1913         SDL_bool grabbed;
  1914         if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
  1915             (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1916             grabbed = SDL_TRUE;
  1917         } else {
  1918             grabbed = SDL_FALSE;
  1919         }
  1920         _this->SetWindowGrab(_this, window, grabbed);
  1921     }
  1922 }
  1923 
  1924 void
  1925 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  1926 {
  1927     CHECK_WINDOW_MAGIC(window, );
  1928 
  1929     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  1930         return;
  1931     }
  1932     if (grabbed) {
  1933         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1934     } else {
  1935         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1936     }
  1937     SDL_UpdateWindowGrab(window);
  1938 }
  1939 
  1940 SDL_bool
  1941 SDL_GetWindowGrab(SDL_Window * window)
  1942 {
  1943     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  1944 
  1945     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1946 }
  1947 
  1948 void
  1949 SDL_OnWindowShown(SDL_Window * window)
  1950 {
  1951     SDL_OnWindowRestored(window);
  1952 }
  1953 
  1954 void
  1955 SDL_OnWindowHidden(SDL_Window * window)
  1956 {
  1957     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1958 }
  1959 
  1960 void
  1961 SDL_OnWindowResized(SDL_Window * window)
  1962 {
  1963     window->surface_valid = SDL_FALSE;
  1964     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  1965 }
  1966 
  1967 void
  1968 SDL_OnWindowMinimized(SDL_Window * window)
  1969 {
  1970     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1971 }
  1972 
  1973 void
  1974 SDL_OnWindowRestored(SDL_Window * window)
  1975 {
  1976     SDL_RaiseWindow(window);
  1977 
  1978     if (FULLSCREEN_VISIBLE(window)) {
  1979         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1980     }
  1981 }
  1982 
  1983 void
  1984 SDL_OnWindowFocusGained(SDL_Window * window)
  1985 {
  1986     if (window->gamma && _this->SetWindowGammaRamp) {
  1987         _this->SetWindowGammaRamp(_this, window, window->gamma);
  1988     }
  1989 
  1990     SDL_UpdateWindowGrab(window);
  1991 }
  1992 
  1993 static SDL_bool ShouldMinimizeOnFocusLoss()
  1994 {
  1995 	const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  1996 	if (hint) {
  1997 		if (*hint == '0') {
  1998 			return SDL_FALSE;
  1999 		} else {
  2000 			return SDL_TRUE;
  2001 		}
  2002 	}
  2003 	return SDL_TRUE;
  2004 }
  2005 
  2006 void
  2007 SDL_OnWindowFocusLost(SDL_Window * window)
  2008 {
  2009     if (window->gamma && _this->SetWindowGammaRamp) {
  2010         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2011     }
  2012 
  2013     SDL_UpdateWindowGrab(window);
  2014 
  2015     /* If we're fullscreen on a single-head system and lose focus, minimize */
  2016 	 if ((window->flags & SDL_WINDOW_FULLSCREEN) && ShouldMinimizeOnFocusLoss() ) {
  2017 			SDL_MinimizeWindow(window);
  2018     }
  2019 }
  2020 
  2021 SDL_Window *
  2022 SDL_GetFocusWindow(void)
  2023 {
  2024     SDL_Window *window;
  2025 
  2026     if (!_this) {
  2027         return NULL;
  2028     }
  2029     for (window = _this->windows; window; window = window->next) {
  2030         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2031             return window;
  2032         }
  2033     }
  2034     return NULL;
  2035 }
  2036 
  2037 void
  2038 SDL_DestroyWindow(SDL_Window * window)
  2039 {
  2040     SDL_VideoDisplay *display;
  2041 
  2042     CHECK_WINDOW_MAGIC(window, );
  2043 
  2044     /* Restore video mode, etc. */
  2045     SDL_HideWindow(window);
  2046 
  2047     /* Make sure this window no longer has focus */
  2048     if (SDL_GetKeyboardFocus() == window) {
  2049         SDL_SetKeyboardFocus(NULL);
  2050     }
  2051     if (SDL_GetMouseFocus() == window) {
  2052         SDL_SetMouseFocus(NULL);
  2053     }
  2054 
  2055     /* make no context current if this is the current context window. */
  2056     if (window->flags & SDL_WINDOW_OPENGL) {
  2057         if (_this->current_glwin == window) {
  2058             SDL_GL_MakeCurrent(window, NULL);
  2059         }
  2060     }
  2061 
  2062     if (window->surface) {
  2063         window->surface->flags &= ~SDL_DONTFREE;
  2064         SDL_FreeSurface(window->surface);
  2065     }
  2066     if (_this->DestroyWindowFramebuffer) {
  2067         _this->DestroyWindowFramebuffer(_this, window);
  2068     }
  2069     if (_this->DestroyWindow) {
  2070         _this->DestroyWindow(_this, window);
  2071     }
  2072     if (window->flags & SDL_WINDOW_OPENGL) {
  2073         SDL_GL_UnloadLibrary();
  2074     }
  2075 
  2076     display = SDL_GetDisplayForWindow(window);
  2077     if (display->fullscreen_window == window) {
  2078         display->fullscreen_window = NULL;
  2079     }
  2080 
  2081     /* Now invalidate magic */
  2082     window->magic = NULL;
  2083 
  2084     /* Free memory associated with the window */
  2085     if (window->title) {
  2086         SDL_free(window->title);
  2087     }
  2088     if (window->gamma) {
  2089         SDL_free(window->gamma);
  2090     }
  2091     while (window->data) {
  2092         SDL_WindowUserData *data = window->data;
  2093 
  2094         window->data = data->next;
  2095         SDL_free(data->name);
  2096         SDL_free(data);
  2097     }
  2098 
  2099     /* Unlink the window from the list */
  2100     if (window->next) {
  2101         window->next->prev = window->prev;
  2102     }
  2103     if (window->prev) {
  2104         window->prev->next = window->next;
  2105     } else {
  2106         _this->windows = window->next;
  2107     }
  2108 
  2109     SDL_free(window);
  2110 }
  2111 
  2112 SDL_bool
  2113 SDL_IsScreenSaverEnabled()
  2114 {
  2115     if (!_this) {
  2116         return SDL_TRUE;
  2117     }
  2118     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2119 }
  2120 
  2121 void
  2122 SDL_EnableScreenSaver()
  2123 {
  2124     if (!_this) {
  2125         return;
  2126     }
  2127     if (!_this->suspend_screensaver) {
  2128         return;
  2129     }
  2130     _this->suspend_screensaver = SDL_FALSE;
  2131     if (_this->SuspendScreenSaver) {
  2132         _this->SuspendScreenSaver(_this);
  2133     }
  2134 }
  2135 
  2136 void
  2137 SDL_DisableScreenSaver()
  2138 {
  2139     if (!_this) {
  2140         return;
  2141     }
  2142     if (_this->suspend_screensaver) {
  2143         return;
  2144     }
  2145     _this->suspend_screensaver = SDL_TRUE;
  2146     if (_this->SuspendScreenSaver) {
  2147         _this->SuspendScreenSaver(_this);
  2148     }
  2149 }
  2150 
  2151 void
  2152 SDL_VideoQuit(void)
  2153 {
  2154     int i, j;
  2155 
  2156     if (!_this) {
  2157         return;
  2158     }
  2159 
  2160     /* Halt event processing before doing anything else */
  2161     SDL_QuitQuit();
  2162     SDL_MouseQuit();
  2163     SDL_KeyboardQuit();
  2164     SDL_StopEventLoop();
  2165 
  2166     SDL_EnableScreenSaver();
  2167 
  2168     /* Clean up the system video */
  2169     while (_this->windows) {
  2170         SDL_DestroyWindow(_this->windows);
  2171     }
  2172     _this->VideoQuit(_this);
  2173 
  2174     for (i = _this->num_displays; i--;) {
  2175         SDL_VideoDisplay *display = &_this->displays[i];
  2176         for (j = display->num_display_modes; j--;) {
  2177             if (display->display_modes[j].driverdata) {
  2178                 SDL_free(display->display_modes[j].driverdata);
  2179                 display->display_modes[j].driverdata = NULL;
  2180             }
  2181         }
  2182         if (display->display_modes) {
  2183             SDL_free(display->display_modes);
  2184             display->display_modes = NULL;
  2185         }
  2186         if (display->desktop_mode.driverdata) {
  2187             SDL_free(display->desktop_mode.driverdata);
  2188             display->desktop_mode.driverdata = NULL;
  2189         }
  2190         if (display->driverdata) {
  2191             SDL_free(display->driverdata);
  2192             display->driverdata = NULL;
  2193         }
  2194     }
  2195     if (_this->displays) {
  2196         SDL_free(_this->displays);
  2197         _this->displays = NULL;
  2198     }
  2199     if (_this->clipboard_text) {
  2200         SDL_free(_this->clipboard_text);
  2201         _this->clipboard_text = NULL;
  2202     }
  2203     _this->free(_this);
  2204     _this = NULL;
  2205 }
  2206 
  2207 int
  2208 SDL_GL_LoadLibrary(const char *path)
  2209 {
  2210     int retval;
  2211 
  2212     if (!_this) {
  2213         SDL_UninitializedVideo();
  2214         return -1;
  2215     }
  2216     if (_this->gl_config.driver_loaded) {
  2217         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2218             SDL_SetError("OpenGL library already loaded");
  2219             return -1;
  2220         }
  2221         retval = 0;
  2222     } else {
  2223         if (!_this->GL_LoadLibrary) {
  2224             SDL_SetError("No dynamic GL support in video driver");
  2225             return -1;
  2226         }
  2227         retval = _this->GL_LoadLibrary(_this, path);
  2228     }
  2229     if (retval == 0) {
  2230         ++_this->gl_config.driver_loaded;
  2231     }
  2232     return (retval);
  2233 }
  2234 
  2235 void *
  2236 SDL_GL_GetProcAddress(const char *proc)
  2237 {
  2238     void *func;
  2239 
  2240     if (!_this) {
  2241         SDL_UninitializedVideo();
  2242         return NULL;
  2243     }
  2244     func = NULL;
  2245     if (_this->GL_GetProcAddress) {
  2246         if (_this->gl_config.driver_loaded) {
  2247             func = _this->GL_GetProcAddress(_this, proc);
  2248         } else {
  2249             SDL_SetError("No GL driver has been loaded");
  2250         }
  2251     } else {
  2252         SDL_SetError("No dynamic GL support in video driver");
  2253     }
  2254     return func;
  2255 }
  2256 
  2257 void
  2258 SDL_GL_UnloadLibrary(void)
  2259 {
  2260     if (!_this) {
  2261         SDL_UninitializedVideo();
  2262         return;
  2263     }
  2264     if (_this->gl_config.driver_loaded > 0) {
  2265         if (--_this->gl_config.driver_loaded > 0) {
  2266             return;
  2267         }
  2268         if (_this->GL_UnloadLibrary) {
  2269             _this->GL_UnloadLibrary(_this);
  2270         }
  2271     }
  2272 }
  2273 
  2274 SDL_bool
  2275 SDL_GL_ExtensionSupported(const char *extension)
  2276 {
  2277 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2278     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2279     const char *extensions;
  2280     const char *start;
  2281     const char *where, *terminator;
  2282 
  2283     /* Extension names should not have spaces. */
  2284     where = SDL_strchr(extension, ' ');
  2285     if (where || *extension == '\0') {
  2286         return SDL_FALSE;
  2287     }
  2288     /* See if there's an environment variable override */
  2289     start = SDL_getenv(extension);
  2290     if (start && *start == '0') {
  2291         return SDL_FALSE;
  2292     }
  2293     /* Lookup the available extensions */
  2294     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2295     if (glGetStringFunc) {
  2296         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2297     } else {
  2298         extensions = NULL;
  2299     }
  2300     if (!extensions) {
  2301         return SDL_FALSE;
  2302     }
  2303     /*
  2304      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2305      * extensions string. Don't be fooled by sub-strings, etc.
  2306      */
  2307 
  2308     start = extensions;
  2309 
  2310     for (;;) {
  2311         where = SDL_strstr(start, extension);
  2312         if (!where)
  2313             break;
  2314 
  2315         terminator = where + SDL_strlen(extension);
  2316         if (where == start || *(where - 1) == ' ')
  2317             if (*terminator == ' ' || *terminator == '\0')
  2318                 return SDL_TRUE;
  2319 
  2320         start = terminator;
  2321     }
  2322     return SDL_FALSE;
  2323 #else
  2324     return SDL_FALSE;
  2325 #endif
  2326 }
  2327 
  2328 int
  2329 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2330 {
  2331 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2332     int retval;
  2333 
  2334     if (!_this) {
  2335         SDL_UninitializedVideo();
  2336         return -1;
  2337     }
  2338     retval = 0;
  2339     switch (attr) {
  2340     case SDL_GL_RED_SIZE:
  2341         _this->gl_config.red_size = value;
  2342         break;
  2343     case SDL_GL_GREEN_SIZE:
  2344         _this->gl_config.green_size = value;
  2345         break;
  2346     case SDL_GL_BLUE_SIZE:
  2347         _this->gl_config.blue_size = value;
  2348         break;
  2349     case SDL_GL_ALPHA_SIZE:
  2350         _this->gl_config.alpha_size = value;
  2351         break;
  2352     case SDL_GL_DOUBLEBUFFER:
  2353         _this->gl_config.double_buffer = value;
  2354         break;
  2355     case SDL_GL_BUFFER_SIZE:
  2356         _this->gl_config.buffer_size = value;
  2357         break;
  2358     case SDL_GL_DEPTH_SIZE:
  2359         _this->gl_config.depth_size = value;
  2360         break;
  2361     case SDL_GL_STENCIL_SIZE:
  2362         _this->gl_config.stencil_size = value;
  2363         break;
  2364     case SDL_GL_ACCUM_RED_SIZE:
  2365         _this->gl_config.accum_red_size = value;
  2366         break;
  2367     case SDL_GL_ACCUM_GREEN_SIZE:
  2368         _this->gl_config.accum_green_size = value;
  2369         break;
  2370     case SDL_GL_ACCUM_BLUE_SIZE:
  2371         _this->gl_config.accum_blue_size = value;
  2372         break;
  2373     case SDL_GL_ACCUM_ALPHA_SIZE:
  2374         _this->gl_config.accum_alpha_size = value;
  2375         break;
  2376     case SDL_GL_STEREO:
  2377         _this->gl_config.stereo = value;
  2378         break;
  2379     case SDL_GL_MULTISAMPLEBUFFERS:
  2380         _this->gl_config.multisamplebuffers = value;
  2381         break;
  2382     case SDL_GL_MULTISAMPLESAMPLES:
  2383         _this->gl_config.multisamplesamples = value;
  2384         break;
  2385     case SDL_GL_ACCELERATED_VISUAL:
  2386         _this->gl_config.accelerated = value;
  2387         break;
  2388     case SDL_GL_RETAINED_BACKING:
  2389         _this->gl_config.retained_backing = value;
  2390         break;
  2391     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2392         _this->gl_config.major_version = value;
  2393         break;
  2394     case SDL_GL_CONTEXT_MINOR_VERSION:
  2395         _this->gl_config.minor_version = value;
  2396         break;
  2397     case SDL_GL_CONTEXT_EGL:
  2398         _this->gl_config.use_egl = value;
  2399         break;
  2400     case SDL_GL_CONTEXT_FLAGS:
  2401         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2402 		      SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2403 		      SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2404 		      SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2405 	    SDL_SetError("Unknown OpenGL context flag %d", value);
  2406 	    retval = -1;
  2407 	    break;
  2408 	}
  2409         _this->gl_config.flags = value;
  2410         break;
  2411     case SDL_GL_CONTEXT_PROFILE_MASK:
  2412         if( value != 0 &&
  2413 	    value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2414 	    value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2415 	    value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2416 	    SDL_SetError("Unknown OpenGL context profile %d", value);
  2417 	    retval = -1;
  2418 	    break;
  2419 	}
  2420         _this->gl_config.profile_mask = value;
  2421         break;
  2422     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2423         _this->gl_config.share_with_current_context = value;
  2424 	break;
  2425     default:
  2426         SDL_SetError("Unknown OpenGL attribute");
  2427         retval = -1;
  2428         break;
  2429     }
  2430     return retval;
  2431 #else
  2432     SDL_Unsupported();
  2433     return -1;
  2434 #endif /* SDL_VIDEO_OPENGL */
  2435 }
  2436 
  2437 int
  2438 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2439 {
  2440 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2441     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2442     GLenum(APIENTRY * glGetErrorFunc) (void);
  2443     GLenum attrib = 0;
  2444     GLenum error = 0;
  2445 
  2446     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2447     if (!glGetIntegervFunc) {
  2448         return -1;
  2449     }
  2450 
  2451     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2452     if (!glGetErrorFunc) {
  2453         return -1;
  2454     }
  2455 
  2456     /* Clear value in any case */
  2457     *value = 0;
  2458 
  2459     switch (attr) {
  2460     case SDL_GL_RED_SIZE:
  2461         attrib = GL_RED_BITS;
  2462         break;
  2463     case SDL_GL_BLUE_SIZE:
  2464         attrib = GL_BLUE_BITS;
  2465         break;
  2466     case SDL_GL_GREEN_SIZE:
  2467         attrib = GL_GREEN_BITS;
  2468         break;
  2469     case SDL_GL_ALPHA_SIZE:
  2470         attrib = GL_ALPHA_BITS;
  2471         break;
  2472     case SDL_GL_DOUBLEBUFFER:
  2473 #if SDL_VIDEO_OPENGL
  2474         attrib = GL_DOUBLEBUFFER;
  2475         break;
  2476 #else
  2477         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2478         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2479         /* SDL driver must set proper value after initialization              */
  2480         *value = _this->gl_config.double_buffer;
  2481         return 0;
  2482 #endif
  2483     case SDL_GL_DEPTH_SIZE:
  2484         attrib = GL_DEPTH_BITS;
  2485         break;
  2486     case SDL_GL_STENCIL_SIZE:
  2487         attrib = GL_STENCIL_BITS;
  2488         break;
  2489 #if SDL_VIDEO_OPENGL
  2490     case SDL_GL_ACCUM_RED_SIZE:
  2491         attrib = GL_ACCUM_RED_BITS;
  2492         break;
  2493     case SDL_GL_ACCUM_GREEN_SIZE:
  2494         attrib = GL_ACCUM_GREEN_BITS;
  2495         break;
  2496     case SDL_GL_ACCUM_BLUE_SIZE:
  2497         attrib = GL_ACCUM_BLUE_BITS;
  2498         break;
  2499     case SDL_GL_ACCUM_ALPHA_SIZE:
  2500         attrib = GL_ACCUM_ALPHA_BITS;
  2501         break;
  2502     case SDL_GL_STEREO:
  2503         attrib = GL_STEREO;
  2504         break;
  2505 #else
  2506     case SDL_GL_ACCUM_RED_SIZE:
  2507     case SDL_GL_ACCUM_GREEN_SIZE:
  2508     case SDL_GL_ACCUM_BLUE_SIZE:
  2509     case SDL_GL_ACCUM_ALPHA_SIZE:
  2510     case SDL_GL_STEREO:
  2511         /* none of these are supported in OpenGL ES */
  2512         *value = 0;
  2513         return 0;
  2514 #endif
  2515     case SDL_GL_MULTISAMPLEBUFFERS:
  2516 #if SDL_VIDEO_OPENGL
  2517         attrib = GL_SAMPLE_BUFFERS_ARB;
  2518 #else
  2519         attrib = GL_SAMPLE_BUFFERS;
  2520 #endif
  2521         break;
  2522     case SDL_GL_MULTISAMPLESAMPLES:
  2523 #if SDL_VIDEO_OPENGL
  2524         attrib = GL_SAMPLES_ARB;
  2525 #else
  2526         attrib = GL_SAMPLES;
  2527 #endif
  2528         break;
  2529     case SDL_GL_BUFFER_SIZE:
  2530         {
  2531             GLint bits = 0;
  2532             GLint component;
  2533 
  2534             /*
  2535              * there doesn't seem to be a single flag in OpenGL
  2536              * for this!
  2537              */
  2538             glGetIntegervFunc(GL_RED_BITS, &component);
  2539             bits += component;
  2540             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2541             bits += component;
  2542             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2543             bits += component;
  2544             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2545             bits += component;
  2546 
  2547             *value = bits;
  2548             return 0;
  2549         }
  2550     case SDL_GL_ACCELERATED_VISUAL:
  2551         {
  2552             /* FIXME: How do we get this information? */
  2553             *value = (_this->gl_config.accelerated != 0);
  2554             return 0;
  2555         }
  2556     case SDL_GL_RETAINED_BACKING:
  2557         {
  2558             *value = _this->gl_config.retained_backing;
  2559             return 0;
  2560         }
  2561     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2562         {
  2563             *value = _this->gl_config.major_version;
  2564             return 0;
  2565         }
  2566     case SDL_GL_CONTEXT_MINOR_VERSION:
  2567         {
  2568             *value = _this->gl_config.minor_version;
  2569             return 0;
  2570         }
  2571     case SDL_GL_CONTEXT_EGL:
  2572         {
  2573             *value = _this->gl_config.use_egl;
  2574             return 0;
  2575         }
  2576     case SDL_GL_CONTEXT_FLAGS:
  2577         {
  2578             *value = _this->gl_config.flags;
  2579             return 0;
  2580         }
  2581     case SDL_GL_CONTEXT_PROFILE_MASK:
  2582         {
  2583             *value = _this->gl_config.profile_mask;
  2584             return 0;
  2585         }
  2586     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2587         {
  2588             *value = _this->gl_config.share_with_current_context;
  2589             return 0;
  2590         }
  2591     default:
  2592         SDL_SetError("Unknown OpenGL attribute");
  2593         return -1;
  2594     }
  2595 
  2596     glGetIntegervFunc(attrib, (GLint *) value);
  2597     error = glGetErrorFunc();
  2598     if (error != GL_NO_ERROR) {
  2599         switch (error) {
  2600         case GL_INVALID_ENUM:
  2601             {
  2602                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2603             }
  2604             break;
  2605         case GL_INVALID_VALUE:
  2606             {
  2607                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2608             }
  2609             break;
  2610         default:
  2611             {
  2612                 SDL_SetError("OpenGL error: %08X", error);
  2613             }
  2614             break;
  2615         }
  2616         return -1;
  2617     }
  2618     return 0;
  2619 #else
  2620     SDL_Unsupported();
  2621     return -1;
  2622 #endif /* SDL_VIDEO_OPENGL */
  2623 }
  2624 
  2625 SDL_GLContext
  2626 SDL_GL_CreateContext(SDL_Window * window)
  2627 {
  2628     SDL_GLContext ctx = NULL;
  2629     CHECK_WINDOW_MAGIC(window, NULL);
  2630 
  2631     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2632         SDL_SetError("The specified window isn't an OpenGL window");
  2633         return NULL;
  2634     }
  2635 
  2636     ctx = _this->GL_CreateContext(_this, window);
  2637 
  2638     /* Creating a context is assumed to make it current in the SDL driver. */
  2639     _this->current_glwin = window;
  2640     _this->current_glctx = ctx;
  2641 
  2642     return ctx;
  2643 }
  2644 
  2645 int
  2646 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2647 {
  2648     int retval;
  2649 
  2650     CHECK_WINDOW_MAGIC(window, -1);
  2651 
  2652     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2653         SDL_SetError("The specified window isn't an OpenGL window");
  2654         return -1;
  2655     }
  2656     if (!ctx) {
  2657         window = NULL;
  2658     }
  2659 
  2660     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
  2661         retval = 0;  /* we're already current. */
  2662     } else {
  2663         retval = _this->GL_MakeCurrent(_this, window, ctx);
  2664         if (retval == 0) {
  2665             _this->current_glwin = window;
  2666             _this->current_glctx = ctx;
  2667         }
  2668     }
  2669 
  2670     return retval;
  2671 }
  2672 
  2673 int
  2674 SDL_GL_SetSwapInterval(int interval)
  2675 {
  2676     if (!_this) {
  2677         SDL_UninitializedVideo();
  2678         return -1;
  2679     } else if (_this->current_glctx == NULL) {
  2680         SDL_SetError("No OpenGL context has been made current");
  2681         return -1;
  2682     } else if (_this->GL_SetSwapInterval) {
  2683         return _this->GL_SetSwapInterval(_this, interval);
  2684     } else {
  2685         SDL_SetError("Setting the swap interval is not supported");
  2686         return -1;
  2687     }
  2688 }
  2689 
  2690 int
  2691 SDL_GL_GetSwapInterval(void)
  2692 {
  2693     if (!_this) {
  2694         return 0;
  2695     } else if (_this->current_glctx == NULL) {
  2696         return 0;
  2697     } else if (_this->GL_GetSwapInterval) {
  2698         return _this->GL_GetSwapInterval(_this);
  2699     } else {
  2700         return 0;
  2701     }
  2702 }
  2703 
  2704 void
  2705 SDL_GL_SwapWindow(SDL_Window * window)
  2706 {
  2707     CHECK_WINDOW_MAGIC(window, );
  2708 
  2709     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2710         SDL_SetError("The specified window isn't an OpenGL window");
  2711         return;
  2712     }
  2713     _this->GL_SwapWindow(_this, window);
  2714 }
  2715 
  2716 void
  2717 SDL_GL_DeleteContext(SDL_GLContext context)
  2718 {
  2719     if (!_this || !context) {
  2720         return;
  2721     }
  2722     _this->GL_MakeCurrent(_this, NULL, NULL);
  2723     _this->GL_DeleteContext(_this, context);
  2724 }
  2725 
  2726 #if 0                           // FIXME
  2727 /*
  2728  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2729  * & 2 for alpha channel.
  2730  */
  2731 static void
  2732 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2733 {
  2734     int x, y;
  2735     Uint32 colorkey;
  2736 #define SET_MASKBIT(icon, x, y, mask) \
  2737 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2738 
  2739     colorkey = icon->format->colorkey;
  2740     switch (icon->format->BytesPerPixel) {
  2741     case 1:
  2742         {
  2743             Uint8 *pixels;
  2744             for (y = 0; y < icon->h; ++y) {
  2745                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2746                 for (x = 0; x < icon->w; ++x) {
  2747                     if (*pixels++ == colorkey) {
  2748                         SET_MASKBIT(icon, x, y, mask);
  2749                     }
  2750                 }
  2751             }
  2752         }
  2753         break;
  2754 
  2755     case 2:
  2756         {
  2757             Uint16 *pixels;
  2758             for (y = 0; y < icon->h; ++y) {
  2759                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2760                 for (x = 0; x < icon->w; ++x) {
  2761                     if ((flags & 1) && *pixels == colorkey) {
  2762                         SET_MASKBIT(icon, x, y, mask);
  2763                     } else if ((flags & 2)
  2764                                && (*pixels & icon->format->Amask) == 0) {
  2765                         SET_MASKBIT(icon, x, y, mask);
  2766                     }
  2767                     pixels++;
  2768                 }
  2769             }
  2770         }
  2771         break;
  2772 
  2773     case 4:
  2774         {
  2775             Uint32 *pixels;
  2776             for (y = 0; y < icon->h; ++y) {
  2777                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2778                 for (x = 0; x < icon->w; ++x) {
  2779                     if ((flags & 1) && *pixels == colorkey) {
  2780                         SET_MASKBIT(icon, x, y, mask);
  2781                     } else if ((flags & 2)
  2782                                && (*pixels & icon->format->Amask) == 0) {
  2783                         SET_MASKBIT(icon, x, y, mask);
  2784                     }
  2785                     pixels++;
  2786                 }
  2787             }
  2788         }
  2789         break;
  2790     }
  2791 }
  2792 
  2793 /*
  2794  * Sets the window manager icon for the display window.
  2795  */
  2796 void
  2797 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2798 {
  2799     if (icon && _this->SetIcon) {
  2800         /* Generate a mask if necessary, and create the icon! */
  2801         if (mask == NULL) {
  2802             int mask_len = icon->h * (icon->w + 7) / 8;
  2803             int flags = 0;
  2804             mask = (Uint8 *) SDL_malloc(mask_len);
  2805             if (mask == NULL) {
  2806                 return;
  2807             }
  2808             SDL_memset(mask, ~0, mask_len);
  2809             if (icon->flags & SDL_SRCCOLORKEY)
  2810                 flags |= 1;
  2811             if (icon->flags & SDL_SRCALPHA)
  2812                 flags |= 2;
  2813             if (flags) {
  2814                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2815             }
  2816             _this->SetIcon(_this, icon, mask);
  2817             SDL_free(mask);
  2818         } else {
  2819             _this->SetIcon(_this, icon, mask);
  2820         }
  2821     }
  2822 }
  2823 #endif
  2824 
  2825 SDL_bool
  2826 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2827 {
  2828     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2829 
  2830     if (!info) {
  2831         return SDL_FALSE;
  2832     }
  2833     info->subsystem = SDL_SYSWM_UNKNOWN;
  2834 
  2835     if (!_this->GetWindowWMInfo) {
  2836         return SDL_FALSE;
  2837     }
  2838     return (_this->GetWindowWMInfo(_this, window, info));
  2839 }
  2840 
  2841 void
  2842 SDL_StartTextInput(void)
  2843 {
  2844     SDL_Window *window;
  2845 
  2846     /* First, enable text events */
  2847     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2848     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2849 
  2850     /* Then show the on-screen keyboard, if any */
  2851     window = SDL_GetFocusWindow();
  2852     if (window && _this && _this->SDL_ShowScreenKeyboard) {
  2853         _this->SDL_ShowScreenKeyboard(_this, window);
  2854     }
  2855 
  2856     /* Finally start the text input system */
  2857     if (_this && _this->StartTextInput) {
  2858         _this->StartTextInput(_this);
  2859     }
  2860 }
  2861 
  2862 SDL_bool
  2863 SDL_IsTextInputActive(void)
  2864 {
  2865     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  2866 }
  2867 
  2868 void
  2869 SDL_StopTextInput(void)
  2870 {
  2871     SDL_Window *window;
  2872 
  2873     /* Stop the text input system */
  2874     if (_this && _this->StopTextInput) {
  2875         _this->StopTextInput(_this);
  2876     }
  2877 
  2878     /* Hide the on-screen keyboard, if any */
  2879     window = SDL_GetFocusWindow();
  2880     if (window && _this && _this->SDL_HideScreenKeyboard) {
  2881         _this->SDL_HideScreenKeyboard(_this, window);
  2882     }
  2883 
  2884     /* Finally disable text events */
  2885     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2886     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2887 }
  2888 
  2889 void
  2890 SDL_SetTextInputRect(SDL_Rect *rect)
  2891 {
  2892     if (_this && _this->SetTextInputRect) {
  2893         _this->SetTextInputRect(_this, rect);
  2894     }
  2895 }
  2896 
  2897 SDL_bool
  2898 SDL_HasScreenKeyboardSupport(void)
  2899 {
  2900     if (_this && _this->SDL_HasScreenKeyboardSupport) {
  2901         return _this->SDL_HasScreenKeyboardSupport(_this);
  2902     }
  2903     return SDL_FALSE;
  2904 }
  2905 
  2906 SDL_bool
  2907 SDL_IsScreenKeyboardShown(SDL_Window *window)
  2908 {
  2909     if (window && _this && _this->SDL_IsScreenKeyboardShown) {
  2910         return _this->SDL_IsScreenKeyboardShown(_this, window);
  2911     }
  2912     return SDL_FALSE;
  2913 }
  2914 
  2915 #if SDL_VIDEO_DRIVER_WINDOWS
  2916 #include "windows/SDL_windowsmessagebox.h"
  2917 #endif
  2918 #if SDL_VIDEO_DRIVER_COCOA
  2919 #include "cocoa/SDL_cocoamessagebox.h"
  2920 #endif
  2921 #if SDL_VIDEO_DRIVER_UIKIT
  2922 #include "uikit/SDL_uikitmessagebox.h"
  2923 #endif
  2924 #if SDL_VIDEO_DRIVER_X11
  2925 #include "x11/SDL_x11messagebox.h"
  2926 #endif
  2927 
  2928 int
  2929 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  2930 {
  2931     int dummybutton;
  2932 
  2933     if (!buttonid) {
  2934         buttonid = &dummybutton;
  2935     }
  2936     if (_this && _this->ShowMessageBox) {
  2937         if (_this->ShowMessageBox(_this, messageboxdata, buttonid) == 0) {
  2938             return 0;
  2939         }
  2940     }
  2941 
  2942     /* It's completely fine to call this function before video is initialized */
  2943 #if SDL_VIDEO_DRIVER_WINDOWS
  2944     if (WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  2945         return 0;
  2946     }
  2947 #endif
  2948 #if SDL_VIDEO_DRIVER_COCOA
  2949     if (Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  2950         return 0;
  2951     }
  2952 #endif
  2953 #if SDL_VIDEO_DRIVER_UIKIT
  2954     if (UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  2955         return 0;
  2956     }
  2957 #endif
  2958 #if SDL_VIDEO_DRIVER_X11
  2959     if (X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  2960         return 0;
  2961     }
  2962 #endif
  2963 
  2964     SDL_SetError("No message system available");
  2965     return -1;
  2966 }
  2967 
  2968 int
  2969 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  2970 {
  2971     SDL_MessageBoxData data;
  2972     SDL_MessageBoxButtonData button;
  2973 
  2974     SDL_zero(data);
  2975     data.flags = flags;
  2976     data.title = title;
  2977     data.message = message;
  2978     data.numbuttons = 1;
  2979     data.buttons = &button;
  2980     data.window = window;
  2981 
  2982     SDL_zero(button);
  2983     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  2984     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  2985     button.text = "OK";
  2986 
  2987     return SDL_ShowMessageBox(&data, NULL);
  2988 }
  2989 
  2990 /* vi: set ts=4 sw=4 expandtab: */