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