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