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