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