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