src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 22 May 2013 01:31:04 -0400
changeset 7210 5b35f3e503c4
parent 7195 d206c3a59b2e
child 7212 81b0d4773d47
permissions -rw-r--r--
Use glGetStringi() for extension lookup on OpenGL contexts >= version 3.0.

Fixes Bugzilla #1620.
     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_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1501         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1502         int displayIndex;
  1503         SDL_Rect bounds;
  1504 
  1505         displayIndex = SDL_GetIndexOfDisplay(display);
  1506         SDL_GetDisplayBounds(displayIndex, &bounds);
  1507         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1508             x = bounds.x + (bounds.w - window->w) / 2;
  1509         }
  1510         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1511             y = bounds.y + (bounds.h - window->h) / 2;
  1512         }
  1513     }
  1514 
  1515     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1516         window->x = x;
  1517     }
  1518     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1519         window->y = y;
  1520     }
  1521 
  1522     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1523         if (_this->SetWindowPosition) {
  1524             _this->SetWindowPosition(_this, window);
  1525         }
  1526         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1527     }
  1528 }
  1529 
  1530 void
  1531 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1532 {
  1533     CHECK_WINDOW_MAGIC(window, );
  1534 
  1535     /* Fullscreen windows are always at their display's origin */
  1536     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1537         if (x) {
  1538             *x = 0;
  1539         }
  1540         if (y) {
  1541             *y = 0;
  1542         }
  1543     } else {
  1544         if (x) {
  1545             *x = window->x;
  1546         }
  1547         if (y) {
  1548             *y = window->y;
  1549         }
  1550     }
  1551 }
  1552 
  1553 void
  1554 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1555 {
  1556     CHECK_WINDOW_MAGIC(window, );
  1557     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1558         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1559         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1560         if ((want != have) && (_this->SetWindowBordered)) {
  1561             if (want) {
  1562                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1563             } else {
  1564                 window->flags |= SDL_WINDOW_BORDERLESS;
  1565             }
  1566             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1567         }
  1568     }
  1569 }
  1570 
  1571 void
  1572 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1573 {
  1574     CHECK_WINDOW_MAGIC(window, );
  1575     if (w <= 0) {
  1576         SDL_InvalidParamError("w");
  1577         return;
  1578     }
  1579     if (h <= 0) {
  1580         SDL_InvalidParamError("h");
  1581         return;
  1582     }
  1583 
  1584     /* FIXME: Should this change fullscreen modes? */
  1585     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1586         window->w = w;
  1587         window->h = h;
  1588         if (_this->SetWindowSize) {
  1589             _this->SetWindowSize(_this, window);
  1590         }
  1591         if (window->w == w && window->h == h) {
  1592             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1593             SDL_OnWindowResized(window);
  1594         }
  1595     }
  1596 }
  1597 
  1598 void
  1599 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1600 {
  1601     CHECK_WINDOW_MAGIC(window, );
  1602     if (w) {
  1603         *w = window->w;
  1604     }
  1605     if (h) {
  1606         *h = window->h;
  1607     }
  1608 }
  1609 
  1610 void
  1611 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1612 {
  1613     CHECK_WINDOW_MAGIC(window, );
  1614     if (min_w <= 0) {
  1615         SDL_InvalidParamError("min_w");
  1616         return;
  1617     }
  1618     if (min_h <= 0) {
  1619         SDL_InvalidParamError("min_h");
  1620         return;
  1621     }
  1622 
  1623     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1624         window->min_w = min_w;
  1625         window->min_h = min_h;
  1626         if (_this->SetWindowMinimumSize) {
  1627             _this->SetWindowMinimumSize(_this, window);
  1628         }
  1629         /* Ensure that window is not smaller than minimal size */
  1630         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1631     }
  1632 }
  1633 
  1634 void
  1635 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1636 {
  1637     CHECK_WINDOW_MAGIC(window, );
  1638     if (min_w) {
  1639         *min_w = window->min_w;
  1640     }
  1641     if (min_h) {
  1642         *min_h = window->min_h;
  1643     }
  1644 }
  1645 
  1646 void
  1647 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1648 {
  1649     CHECK_WINDOW_MAGIC(window, );
  1650     if (max_w <= 0) {
  1651         SDL_InvalidParamError("max_w");
  1652         return;
  1653     }
  1654     if (max_h <= 0) {
  1655         SDL_InvalidParamError("max_h");
  1656         return;
  1657     }
  1658 
  1659     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1660         window->max_w = max_w;
  1661         window->max_h = max_h;
  1662         if (_this->SetWindowMaximumSize) {
  1663             _this->SetWindowMaximumSize(_this, window);
  1664         }
  1665         /* Ensure that window is not larger than maximal size */
  1666         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1667     }
  1668 }
  1669 
  1670 void
  1671 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1672 {
  1673     CHECK_WINDOW_MAGIC(window, );
  1674     if (max_w) {
  1675         *max_w = window->max_w;
  1676     }
  1677     if (max_h) {
  1678         *max_h = window->max_h;
  1679     }
  1680 }
  1681 
  1682 void
  1683 SDL_ShowWindow(SDL_Window * window)
  1684 {
  1685     CHECK_WINDOW_MAGIC(window, );
  1686 
  1687     if (window->flags & SDL_WINDOW_SHOWN) {
  1688         return;
  1689     }
  1690 
  1691     if (_this->ShowWindow) {
  1692         _this->ShowWindow(_this, window);
  1693     }
  1694     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1695 }
  1696 
  1697 void
  1698 SDL_HideWindow(SDL_Window * window)
  1699 {
  1700     CHECK_WINDOW_MAGIC(window, );
  1701 
  1702     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1703         return;
  1704     }
  1705 
  1706     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1707 
  1708     if (_this->HideWindow) {
  1709         _this->HideWindow(_this, window);
  1710     }
  1711     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1712 }
  1713 
  1714 void
  1715 SDL_RaiseWindow(SDL_Window * window)
  1716 {
  1717     CHECK_WINDOW_MAGIC(window, );
  1718 
  1719     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1720         return;
  1721     }
  1722     if (_this->RaiseWindow) {
  1723         _this->RaiseWindow(_this, window);
  1724     }
  1725 }
  1726 
  1727 void
  1728 SDL_MaximizeWindow(SDL_Window * window)
  1729 {
  1730     CHECK_WINDOW_MAGIC(window, );
  1731 
  1732     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1733         return;
  1734     }
  1735 
  1736     if (_this->MaximizeWindow) {
  1737         _this->MaximizeWindow(_this, window);
  1738     }
  1739 }
  1740 
  1741 void
  1742 SDL_MinimizeWindow(SDL_Window * window)
  1743 {
  1744     CHECK_WINDOW_MAGIC(window, );
  1745 
  1746     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1747         return;
  1748     }
  1749 
  1750     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1751 
  1752     if (_this->MinimizeWindow) {
  1753         _this->MinimizeWindow(_this, window);
  1754     }
  1755 }
  1756 
  1757 void
  1758 SDL_RestoreWindow(SDL_Window * window)
  1759 {
  1760     CHECK_WINDOW_MAGIC(window, );
  1761 
  1762     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1763         return;
  1764     }
  1765 
  1766     if (_this->RestoreWindow) {
  1767         _this->RestoreWindow(_this, window);
  1768     }
  1769 }
  1770 
  1771 #define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN )
  1772 int
  1773 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1774 {
  1775     CHECK_WINDOW_MAGIC(window, -1);
  1776 
  1777     flags &= FULLSCREEN_MASK;
  1778 
  1779     if ( flags == (window->flags & FULLSCREEN_MASK) ) {
  1780         return 0;
  1781     }
  1782 
  1783     /* clear the previous flags and OR in the new ones */
  1784     window->flags &= ~FULLSCREEN_MASK;
  1785     window->flags |= flags;
  1786 
  1787     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1788 
  1789     return 0;
  1790 }
  1791 
  1792 static SDL_Surface *
  1793 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1794 {
  1795     Uint32 format;
  1796     void *pixels;
  1797     int pitch;
  1798     int bpp;
  1799     Uint32 Rmask, Gmask, Bmask, Amask;
  1800 
  1801     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1802         return NULL;
  1803     }
  1804 
  1805     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1806         return NULL;
  1807     }
  1808 
  1809     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1810         return NULL;
  1811     }
  1812 
  1813     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1814 }
  1815 
  1816 SDL_Surface *
  1817 SDL_GetWindowSurface(SDL_Window * window)
  1818 {
  1819     CHECK_WINDOW_MAGIC(window, NULL);
  1820 
  1821     if (!window->surface_valid) {
  1822         if (window->surface) {
  1823             window->surface->flags &= ~SDL_DONTFREE;
  1824             SDL_FreeSurface(window->surface);
  1825         }
  1826         window->surface = SDL_CreateWindowFramebuffer(window);
  1827         if (window->surface) {
  1828             window->surface_valid = SDL_TRUE;
  1829             window->surface->flags |= SDL_DONTFREE;
  1830         }
  1831     }
  1832     return window->surface;
  1833 }
  1834 
  1835 int
  1836 SDL_UpdateWindowSurface(SDL_Window * window)
  1837 {
  1838     SDL_Rect full_rect;
  1839 
  1840     CHECK_WINDOW_MAGIC(window, -1);
  1841 
  1842     full_rect.x = 0;
  1843     full_rect.y = 0;
  1844     full_rect.w = window->w;
  1845     full_rect.h = window->h;
  1846     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1847 }
  1848 
  1849 int
  1850 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  1851                              int numrects)
  1852 {
  1853     CHECK_WINDOW_MAGIC(window, -1);
  1854 
  1855     if (!window->surface_valid) {
  1856         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1857     }
  1858 
  1859     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1860 }
  1861 
  1862 int
  1863 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1864 {
  1865     Uint16 ramp[256];
  1866     int status;
  1867 
  1868     CHECK_WINDOW_MAGIC(window, -1);
  1869 
  1870     SDL_CalculateGammaRamp(brightness, ramp);
  1871     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1872     if (status == 0) {
  1873         window->brightness = brightness;
  1874     }
  1875     return status;
  1876 }
  1877 
  1878 float
  1879 SDL_GetWindowBrightness(SDL_Window * window)
  1880 {
  1881     CHECK_WINDOW_MAGIC(window, 1.0f);
  1882 
  1883     return window->brightness;
  1884 }
  1885 
  1886 int
  1887 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1888                                             const Uint16 * green,
  1889                                             const Uint16 * blue)
  1890 {
  1891     CHECK_WINDOW_MAGIC(window, -1);
  1892 
  1893     if (!_this->SetWindowGammaRamp) {
  1894         return SDL_Unsupported();
  1895     }
  1896 
  1897     if (!window->gamma) {
  1898         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1899             return -1;
  1900         }
  1901     }
  1902 
  1903     if (red) {
  1904         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1905     }
  1906     if (green) {
  1907         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1908     }
  1909     if (blue) {
  1910         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1911     }
  1912     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1913         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1914     } else {
  1915         return 0;
  1916     }
  1917 }
  1918 
  1919 int
  1920 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  1921                                             Uint16 * green,
  1922                                             Uint16 * blue)
  1923 {
  1924     CHECK_WINDOW_MAGIC(window, -1);
  1925 
  1926     if (!window->gamma) {
  1927         int i;
  1928 
  1929         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  1930         if (!window->gamma) {
  1931             return SDL_OutOfMemory();
  1932         }
  1933         window->saved_gamma = window->gamma + 3*256;
  1934 
  1935         if (_this->GetWindowGammaRamp) {
  1936             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  1937                 return -1;
  1938             }
  1939         } else {
  1940             /* Create an identity gamma ramp */
  1941             for (i = 0; i < 256; ++i) {
  1942                 Uint16 value = (Uint16)((i << 8) | i);
  1943 
  1944                 window->gamma[0*256+i] = value;
  1945                 window->gamma[1*256+i] = value;
  1946                 window->gamma[2*256+i] = value;
  1947             }
  1948         }
  1949         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  1950     }
  1951 
  1952     if (red) {
  1953         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  1954     }
  1955     if (green) {
  1956         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  1957     }
  1958     if (blue) {
  1959         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  1960     }
  1961     return 0;
  1962 }
  1963 
  1964 void
  1965 SDL_UpdateWindowGrab(SDL_Window * window)
  1966 {
  1967     if (_this->SetWindowGrab) {
  1968         SDL_bool grabbed;
  1969         if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
  1970             (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1971             grabbed = SDL_TRUE;
  1972         } else {
  1973             grabbed = SDL_FALSE;
  1974         }
  1975         _this->SetWindowGrab(_this, window, grabbed);
  1976     }
  1977 }
  1978 
  1979 void
  1980 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  1981 {
  1982     CHECK_WINDOW_MAGIC(window, );
  1983 
  1984     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  1985         return;
  1986     }
  1987     if (grabbed) {
  1988         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1989     } else {
  1990         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1991     }
  1992     SDL_UpdateWindowGrab(window);
  1993 }
  1994 
  1995 SDL_bool
  1996 SDL_GetWindowGrab(SDL_Window * window)
  1997 {
  1998     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  1999 
  2000     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  2001 }
  2002 
  2003 void
  2004 SDL_OnWindowShown(SDL_Window * window)
  2005 {
  2006     SDL_OnWindowRestored(window);
  2007 }
  2008 
  2009 void
  2010 SDL_OnWindowHidden(SDL_Window * window)
  2011 {
  2012     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2013 }
  2014 
  2015 void
  2016 SDL_OnWindowResized(SDL_Window * window)
  2017 {
  2018     window->surface_valid = SDL_FALSE;
  2019     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2020 }
  2021 
  2022 void
  2023 SDL_OnWindowMinimized(SDL_Window * window)
  2024 {
  2025     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2026 }
  2027 
  2028 void
  2029 SDL_OnWindowRestored(SDL_Window * window)
  2030 {
  2031     SDL_RaiseWindow(window);
  2032 
  2033     if (FULLSCREEN_VISIBLE(window)) {
  2034         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2035     }
  2036 }
  2037 
  2038 void
  2039 SDL_OnWindowEnter(SDL_Window * window)
  2040 {
  2041     if (_this->OnWindowEnter) {
  2042         _this->OnWindowEnter(_this, window);
  2043     }
  2044 }
  2045 
  2046 void
  2047 SDL_OnWindowLeave(SDL_Window * window)
  2048 {
  2049 }
  2050 
  2051 void
  2052 SDL_OnWindowFocusGained(SDL_Window * window)
  2053 {
  2054     SDL_Mouse *mouse = SDL_GetMouse();
  2055 
  2056     if (window->gamma && _this->SetWindowGammaRamp) {
  2057         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2058     }
  2059 
  2060     if (mouse && mouse->relative_mode) {
  2061         SDL_SetMouseFocus(window);
  2062         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2063     }
  2064 
  2065     SDL_UpdateWindowGrab(window);
  2066 }
  2067 
  2068 static SDL_bool ShouldMinimizeOnFocusLoss()
  2069 {
  2070     const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2071     if (hint) {
  2072         if (*hint == '0') {
  2073             return SDL_FALSE;
  2074         } else {
  2075             return SDL_TRUE;
  2076         }
  2077     }
  2078     return SDL_TRUE;
  2079 }
  2080 
  2081 void
  2082 SDL_OnWindowFocusLost(SDL_Window * window)
  2083 {
  2084     if (window->gamma && _this->SetWindowGammaRamp) {
  2085         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2086     }
  2087 
  2088     SDL_UpdateWindowGrab(window);
  2089 
  2090     /* If we're fullscreen on a single-head system and lose focus, minimize */
  2091      if ((window->flags & SDL_WINDOW_FULLSCREEN) && ShouldMinimizeOnFocusLoss() ) {
  2092             SDL_MinimizeWindow(window);
  2093     }
  2094 }
  2095 
  2096 SDL_Window *
  2097 SDL_GetFocusWindow(void)
  2098 {
  2099     SDL_Window *window;
  2100 
  2101     if (!_this) {
  2102         return NULL;
  2103     }
  2104     for (window = _this->windows; window; window = window->next) {
  2105         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2106             return window;
  2107         }
  2108     }
  2109     return NULL;
  2110 }
  2111 
  2112 void
  2113 SDL_DestroyWindow(SDL_Window * window)
  2114 {
  2115     SDL_VideoDisplay *display;
  2116 
  2117     CHECK_WINDOW_MAGIC(window, );
  2118 
  2119     /* Restore video mode, etc. */
  2120     SDL_HideWindow(window);
  2121 
  2122     /* Make sure this window no longer has focus */
  2123     if (SDL_GetKeyboardFocus() == window) {
  2124         SDL_SetKeyboardFocus(NULL);
  2125     }
  2126     if (SDL_GetMouseFocus() == window) {
  2127         SDL_SetMouseFocus(NULL);
  2128     }
  2129 
  2130     /* make no context current if this is the current context window. */
  2131     if (window->flags & SDL_WINDOW_OPENGL) {
  2132         if (_this->current_glwin == window) {
  2133             SDL_GL_MakeCurrent(window, NULL);
  2134         }
  2135     }
  2136 
  2137     if (window->surface) {
  2138         window->surface->flags &= ~SDL_DONTFREE;
  2139         SDL_FreeSurface(window->surface);
  2140     }
  2141     if (_this->DestroyWindowFramebuffer) {
  2142         _this->DestroyWindowFramebuffer(_this, window);
  2143     }
  2144     if (_this->DestroyWindow) {
  2145         _this->DestroyWindow(_this, window);
  2146     }
  2147     if (window->flags & SDL_WINDOW_OPENGL) {
  2148         SDL_GL_UnloadLibrary();
  2149     }
  2150 
  2151     display = SDL_GetDisplayForWindow(window);
  2152     if (display->fullscreen_window == window) {
  2153         display->fullscreen_window = NULL;
  2154     }
  2155 
  2156     /* Now invalidate magic */
  2157     window->magic = NULL;
  2158 
  2159     /* Free memory associated with the window */
  2160     if (window->title) {
  2161         SDL_free(window->title);
  2162     }
  2163     if (window->gamma) {
  2164         SDL_free(window->gamma);
  2165     }
  2166     while (window->data) {
  2167         SDL_WindowUserData *data = window->data;
  2168 
  2169         window->data = data->next;
  2170         SDL_free(data->name);
  2171         SDL_free(data);
  2172     }
  2173 
  2174     /* Unlink the window from the list */
  2175     if (window->next) {
  2176         window->next->prev = window->prev;
  2177     }
  2178     if (window->prev) {
  2179         window->prev->next = window->next;
  2180     } else {
  2181         _this->windows = window->next;
  2182     }
  2183 
  2184     SDL_free(window);
  2185 }
  2186 
  2187 SDL_bool
  2188 SDL_IsScreenSaverEnabled()
  2189 {
  2190     if (!_this) {
  2191         return SDL_TRUE;
  2192     }
  2193     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2194 }
  2195 
  2196 void
  2197 SDL_EnableScreenSaver()
  2198 {
  2199     if (!_this) {
  2200         return;
  2201     }
  2202     if (!_this->suspend_screensaver) {
  2203         return;
  2204     }
  2205     _this->suspend_screensaver = SDL_FALSE;
  2206     if (_this->SuspendScreenSaver) {
  2207         _this->SuspendScreenSaver(_this);
  2208     }
  2209 }
  2210 
  2211 void
  2212 SDL_DisableScreenSaver()
  2213 {
  2214     if (!_this) {
  2215         return;
  2216     }
  2217     if (_this->suspend_screensaver) {
  2218         return;
  2219     }
  2220     _this->suspend_screensaver = SDL_TRUE;
  2221     if (_this->SuspendScreenSaver) {
  2222         _this->SuspendScreenSaver(_this);
  2223     }
  2224 }
  2225 
  2226 void
  2227 SDL_VideoQuit(void)
  2228 {
  2229     int i, j;
  2230 
  2231     if (!_this) {
  2232         return;
  2233     }
  2234 
  2235     /* Halt event processing before doing anything else */
  2236     SDL_QuitQuit();
  2237     SDL_MouseQuit();
  2238     SDL_KeyboardQuit();
  2239     SDL_StopEventLoop();
  2240 
  2241     SDL_EnableScreenSaver();
  2242 
  2243     /* Clean up the system video */
  2244     while (_this->windows) {
  2245         SDL_DestroyWindow(_this->windows);
  2246     }
  2247     _this->VideoQuit(_this);
  2248 
  2249     for (i = _this->num_displays; i--;) {
  2250         SDL_VideoDisplay *display = &_this->displays[i];
  2251         for (j = display->num_display_modes; j--;) {
  2252             if (display->display_modes[j].driverdata) {
  2253                 SDL_free(display->display_modes[j].driverdata);
  2254                 display->display_modes[j].driverdata = NULL;
  2255             }
  2256         }
  2257         if (display->display_modes) {
  2258             SDL_free(display->display_modes);
  2259             display->display_modes = NULL;
  2260         }
  2261         if (display->desktop_mode.driverdata) {
  2262             SDL_free(display->desktop_mode.driverdata);
  2263             display->desktop_mode.driverdata = NULL;
  2264         }
  2265         if (display->driverdata) {
  2266             SDL_free(display->driverdata);
  2267             display->driverdata = NULL;
  2268         }
  2269     }
  2270     if (_this->displays) {
  2271         for (i = 0; i < _this->num_displays; ++i) {
  2272             SDL_free(_this->displays[i].name);
  2273         }
  2274         SDL_free(_this->displays);
  2275         _this->displays = NULL;
  2276         _this->num_displays = 0;
  2277     }
  2278     if (_this->clipboard_text) {
  2279         SDL_free(_this->clipboard_text);
  2280         _this->clipboard_text = NULL;
  2281     }
  2282     _this->free(_this);
  2283     _this = NULL;
  2284 }
  2285 
  2286 int
  2287 SDL_GL_LoadLibrary(const char *path)
  2288 {
  2289     int retval;
  2290 
  2291     if (!_this) {
  2292         return SDL_UninitializedVideo();
  2293     }
  2294     if (_this->gl_config.driver_loaded) {
  2295         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2296             return SDL_SetError("OpenGL library already loaded");
  2297         }
  2298         retval = 0;
  2299     } else {
  2300         if (!_this->GL_LoadLibrary) {
  2301             return  SDL_SetError("No dynamic GL support in video driver");
  2302         }
  2303         retval = _this->GL_LoadLibrary(_this, path);
  2304     }
  2305     if (retval == 0) {
  2306         ++_this->gl_config.driver_loaded;
  2307     }
  2308     return (retval);
  2309 }
  2310 
  2311 void *
  2312 SDL_GL_GetProcAddress(const char *proc)
  2313 {
  2314     void *func;
  2315 
  2316     if (!_this) {
  2317         SDL_UninitializedVideo();
  2318         return NULL;
  2319     }
  2320     func = NULL;
  2321     if (_this->GL_GetProcAddress) {
  2322         if (_this->gl_config.driver_loaded) {
  2323             func = _this->GL_GetProcAddress(_this, proc);
  2324         } else {
  2325             SDL_SetError("No GL driver has been loaded");
  2326         }
  2327     } else {
  2328         SDL_SetError("No dynamic GL support in video driver");
  2329     }
  2330     return func;
  2331 }
  2332 
  2333 void
  2334 SDL_GL_UnloadLibrary(void)
  2335 {
  2336     if (!_this) {
  2337         SDL_UninitializedVideo();
  2338         return;
  2339     }
  2340     if (_this->gl_config.driver_loaded > 0) {
  2341         if (--_this->gl_config.driver_loaded > 0) {
  2342             return;
  2343         }
  2344         if (_this->GL_UnloadLibrary) {
  2345             _this->GL_UnloadLibrary(_this);
  2346         }
  2347     }
  2348 }
  2349 
  2350 static __inline__ SDL_bool
  2351 isAtLeastGL3(const char *verstr)
  2352 {
  2353     return ( verstr && (SDL_atoi(verstr) >= 3) );
  2354 }
  2355 
  2356 SDL_bool
  2357 SDL_GL_ExtensionSupported(const char *extension)
  2358 {
  2359 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2360     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2361     const char *extensions;
  2362     const char *start;
  2363     const char *where, *terminator;
  2364 
  2365     /* Extension names should not have spaces. */
  2366     where = SDL_strchr(extension, ' ');
  2367     if (where || *extension == '\0') {
  2368         return SDL_FALSE;
  2369     }
  2370     /* See if there's an environment variable override */
  2371     start = SDL_getenv(extension);
  2372     if (start && *start == '0') {
  2373         return SDL_FALSE;
  2374     }
  2375 
  2376     /* Lookup the available extensions */
  2377 
  2378     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2379     if (!glGetStringFunc) {
  2380         return SDL_FALSE;
  2381     }
  2382 
  2383     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2384         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2385         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2386         GLint num_exts = 0;
  2387         GLint i;
  2388 
  2389         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2390         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2391         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2392             return SDL_FALSE;
  2393         }
  2394 
  2395         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2396         for (i = 0; i < num_exts; i++) {
  2397             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2398             if (SDL_strcmp(thisext, extension) == 0) {
  2399                 return SDL_TRUE;
  2400             }
  2401         }
  2402 
  2403         return SDL_FALSE;
  2404     }
  2405 
  2406     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2407 
  2408     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2409     if (!extensions) {
  2410         return SDL_FALSE;
  2411     }
  2412     /*
  2413      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2414      * extensions string. Don't be fooled by sub-strings, etc.
  2415      */
  2416 
  2417     start = extensions;
  2418 
  2419     for (;;) {
  2420         where = SDL_strstr(start, extension);
  2421         if (!where)
  2422             break;
  2423 
  2424         terminator = where + SDL_strlen(extension);
  2425         if (where == start || *(where - 1) == ' ')
  2426             if (*terminator == ' ' || *terminator == '\0')
  2427                 return SDL_TRUE;
  2428 
  2429         start = terminator;
  2430     }
  2431     return SDL_FALSE;
  2432 #else
  2433     return SDL_FALSE;
  2434 #endif
  2435 }
  2436 
  2437 int
  2438 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2439 {
  2440 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2441     int retval;
  2442 
  2443     if (!_this) {
  2444         return SDL_UninitializedVideo();
  2445     }
  2446     retval = 0;
  2447     switch (attr) {
  2448     case SDL_GL_RED_SIZE:
  2449         _this->gl_config.red_size = value;
  2450         break;
  2451     case SDL_GL_GREEN_SIZE:
  2452         _this->gl_config.green_size = value;
  2453         break;
  2454     case SDL_GL_BLUE_SIZE:
  2455         _this->gl_config.blue_size = value;
  2456         break;
  2457     case SDL_GL_ALPHA_SIZE:
  2458         _this->gl_config.alpha_size = value;
  2459         break;
  2460     case SDL_GL_DOUBLEBUFFER:
  2461         _this->gl_config.double_buffer = value;
  2462         break;
  2463     case SDL_GL_BUFFER_SIZE:
  2464         _this->gl_config.buffer_size = value;
  2465         break;
  2466     case SDL_GL_DEPTH_SIZE:
  2467         _this->gl_config.depth_size = value;
  2468         break;
  2469     case SDL_GL_STENCIL_SIZE:
  2470         _this->gl_config.stencil_size = value;
  2471         break;
  2472     case SDL_GL_ACCUM_RED_SIZE:
  2473         _this->gl_config.accum_red_size = value;
  2474         break;
  2475     case SDL_GL_ACCUM_GREEN_SIZE:
  2476         _this->gl_config.accum_green_size = value;
  2477         break;
  2478     case SDL_GL_ACCUM_BLUE_SIZE:
  2479         _this->gl_config.accum_blue_size = value;
  2480         break;
  2481     case SDL_GL_ACCUM_ALPHA_SIZE:
  2482         _this->gl_config.accum_alpha_size = value;
  2483         break;
  2484     case SDL_GL_STEREO:
  2485         _this->gl_config.stereo = value;
  2486         break;
  2487     case SDL_GL_MULTISAMPLEBUFFERS:
  2488         _this->gl_config.multisamplebuffers = value;
  2489         break;
  2490     case SDL_GL_MULTISAMPLESAMPLES:
  2491         _this->gl_config.multisamplesamples = value;
  2492         break;
  2493     case SDL_GL_ACCELERATED_VISUAL:
  2494         _this->gl_config.accelerated = value;
  2495         break;
  2496     case SDL_GL_RETAINED_BACKING:
  2497         _this->gl_config.retained_backing = value;
  2498         break;
  2499     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2500         _this->gl_config.major_version = value;
  2501         break;
  2502     case SDL_GL_CONTEXT_MINOR_VERSION:
  2503         _this->gl_config.minor_version = value;
  2504         break;
  2505     case SDL_GL_CONTEXT_EGL:
  2506         _this->gl_config.use_egl = value;
  2507         break;
  2508     case SDL_GL_CONTEXT_FLAGS:
  2509         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2510               SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2511               SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2512               SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2513         retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2514         break;
  2515     }
  2516         _this->gl_config.flags = value;
  2517         break;
  2518     case SDL_GL_CONTEXT_PROFILE_MASK:
  2519         if( value != 0 &&
  2520         value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2521         value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2522         value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2523         retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2524         break;
  2525     }
  2526         _this->gl_config.profile_mask = value;
  2527         break;
  2528     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2529         _this->gl_config.share_with_current_context = value;
  2530     break;
  2531     default:
  2532         retval = SDL_SetError("Unknown OpenGL attribute");
  2533         break;
  2534     }
  2535     return retval;
  2536 #else
  2537     return SDL_Unsupported();
  2538 #endif /* SDL_VIDEO_OPENGL */
  2539 }
  2540 
  2541 int
  2542 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2543 {
  2544 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2545     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2546     GLenum(APIENTRY * glGetErrorFunc) (void);
  2547     GLenum attrib = 0;
  2548     GLenum error = 0;
  2549 
  2550     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2551     if (!glGetIntegervFunc) {
  2552         return -1;
  2553     }
  2554 
  2555     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2556     if (!glGetErrorFunc) {
  2557         return -1;
  2558     }
  2559 
  2560     /* Clear value in any case */
  2561     *value = 0;
  2562 
  2563     switch (attr) {
  2564     case SDL_GL_RED_SIZE:
  2565         attrib = GL_RED_BITS;
  2566         break;
  2567     case SDL_GL_BLUE_SIZE:
  2568         attrib = GL_BLUE_BITS;
  2569         break;
  2570     case SDL_GL_GREEN_SIZE:
  2571         attrib = GL_GREEN_BITS;
  2572         break;
  2573     case SDL_GL_ALPHA_SIZE:
  2574         attrib = GL_ALPHA_BITS;
  2575         break;
  2576     case SDL_GL_DOUBLEBUFFER:
  2577 #if SDL_VIDEO_OPENGL
  2578         attrib = GL_DOUBLEBUFFER;
  2579         break;
  2580 #else
  2581         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2582         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2583         /* SDL driver must set proper value after initialization              */
  2584         *value = _this->gl_config.double_buffer;
  2585         return 0;
  2586 #endif
  2587     case SDL_GL_DEPTH_SIZE:
  2588         attrib = GL_DEPTH_BITS;
  2589         break;
  2590     case SDL_GL_STENCIL_SIZE:
  2591         attrib = GL_STENCIL_BITS;
  2592         break;
  2593 #if SDL_VIDEO_OPENGL
  2594     case SDL_GL_ACCUM_RED_SIZE:
  2595         attrib = GL_ACCUM_RED_BITS;
  2596         break;
  2597     case SDL_GL_ACCUM_GREEN_SIZE:
  2598         attrib = GL_ACCUM_GREEN_BITS;
  2599         break;
  2600     case SDL_GL_ACCUM_BLUE_SIZE:
  2601         attrib = GL_ACCUM_BLUE_BITS;
  2602         break;
  2603     case SDL_GL_ACCUM_ALPHA_SIZE:
  2604         attrib = GL_ACCUM_ALPHA_BITS;
  2605         break;
  2606     case SDL_GL_STEREO:
  2607         attrib = GL_STEREO;
  2608         break;
  2609 #else
  2610     case SDL_GL_ACCUM_RED_SIZE:
  2611     case SDL_GL_ACCUM_GREEN_SIZE:
  2612     case SDL_GL_ACCUM_BLUE_SIZE:
  2613     case SDL_GL_ACCUM_ALPHA_SIZE:
  2614     case SDL_GL_STEREO:
  2615         /* none of these are supported in OpenGL ES */
  2616         *value = 0;
  2617         return 0;
  2618 #endif
  2619     case SDL_GL_MULTISAMPLEBUFFERS:
  2620 #if SDL_VIDEO_OPENGL
  2621         attrib = GL_SAMPLE_BUFFERS_ARB;
  2622 #else
  2623         attrib = GL_SAMPLE_BUFFERS;
  2624 #endif
  2625         break;
  2626     case SDL_GL_MULTISAMPLESAMPLES:
  2627 #if SDL_VIDEO_OPENGL
  2628         attrib = GL_SAMPLES_ARB;
  2629 #else
  2630         attrib = GL_SAMPLES;
  2631 #endif
  2632         break;
  2633     case SDL_GL_BUFFER_SIZE:
  2634         {
  2635             GLint bits = 0;
  2636             GLint component;
  2637 
  2638             /*
  2639              * there doesn't seem to be a single flag in OpenGL
  2640              * for this!
  2641              */
  2642             glGetIntegervFunc(GL_RED_BITS, &component);
  2643             bits += component;
  2644             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2645             bits += component;
  2646             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2647             bits += component;
  2648             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2649             bits += component;
  2650 
  2651             *value = bits;
  2652             return 0;
  2653         }
  2654     case SDL_GL_ACCELERATED_VISUAL:
  2655         {
  2656             /* FIXME: How do we get this information? */
  2657             *value = (_this->gl_config.accelerated != 0);
  2658             return 0;
  2659         }
  2660     case SDL_GL_RETAINED_BACKING:
  2661         {
  2662             *value = _this->gl_config.retained_backing;
  2663             return 0;
  2664         }
  2665     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2666         {
  2667             *value = _this->gl_config.major_version;
  2668             return 0;
  2669         }
  2670     case SDL_GL_CONTEXT_MINOR_VERSION:
  2671         {
  2672             *value = _this->gl_config.minor_version;
  2673             return 0;
  2674         }
  2675     case SDL_GL_CONTEXT_EGL:
  2676         {
  2677             *value = _this->gl_config.use_egl;
  2678             return 0;
  2679         }
  2680     case SDL_GL_CONTEXT_FLAGS:
  2681         {
  2682             *value = _this->gl_config.flags;
  2683             return 0;
  2684         }
  2685     case SDL_GL_CONTEXT_PROFILE_MASK:
  2686         {
  2687             *value = _this->gl_config.profile_mask;
  2688             return 0;
  2689         }
  2690     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2691         {
  2692             *value = _this->gl_config.share_with_current_context;
  2693             return 0;
  2694         }
  2695     default:
  2696         return SDL_SetError("Unknown OpenGL attribute");
  2697     }
  2698 
  2699     glGetIntegervFunc(attrib, (GLint *) value);
  2700     error = glGetErrorFunc();
  2701     if (error != GL_NO_ERROR) {
  2702         if (error == GL_INVALID_ENUM) {
  2703             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2704         } else if (error == GL_INVALID_VALUE) {
  2705             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2706         }
  2707         return SDL_SetError("OpenGL error: %08X", error);
  2708     }
  2709     return 0;
  2710 #else
  2711     return SDL_Unsupported();
  2712 #endif /* SDL_VIDEO_OPENGL */
  2713 }
  2714 
  2715 SDL_GLContext
  2716 SDL_GL_CreateContext(SDL_Window * window)
  2717 {
  2718     SDL_GLContext ctx = NULL;
  2719     CHECK_WINDOW_MAGIC(window, NULL);
  2720 
  2721     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2722         SDL_SetError("The specified window isn't an OpenGL window");
  2723         return NULL;
  2724     }
  2725 
  2726     ctx = _this->GL_CreateContext(_this, window);
  2727 
  2728     /* Creating a context is assumed to make it current in the SDL driver. */
  2729     _this->current_glwin = window;
  2730     _this->current_glctx = ctx;
  2731 
  2732     return ctx;
  2733 }
  2734 
  2735 int
  2736 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2737 {
  2738     int retval;
  2739 
  2740     if (!ctx) {
  2741         window = NULL;
  2742     } else {
  2743         CHECK_WINDOW_MAGIC(window, -1);
  2744 
  2745         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2746             return SDL_SetError("The specified window isn't an OpenGL window");
  2747         }
  2748     }
  2749 
  2750     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
  2751         retval = 0;  /* we're already current. */
  2752     } else {
  2753         retval = _this->GL_MakeCurrent(_this, window, ctx);
  2754         if (retval == 0) {
  2755             _this->current_glwin = window;
  2756             _this->current_glctx = ctx;
  2757         }
  2758     }
  2759 
  2760     return retval;
  2761 }
  2762 
  2763 int
  2764 SDL_GL_SetSwapInterval(int interval)
  2765 {
  2766     if (!_this) {
  2767         return SDL_UninitializedVideo();
  2768     } else if (_this->current_glctx == NULL) {
  2769         return SDL_SetError("No OpenGL context has been made current");
  2770     } else if (_this->GL_SetSwapInterval) {
  2771         return _this->GL_SetSwapInterval(_this, interval);
  2772     } else {
  2773         return SDL_SetError("Setting the swap interval is not supported");
  2774     }
  2775 }
  2776 
  2777 int
  2778 SDL_GL_GetSwapInterval(void)
  2779 {
  2780     if (!_this) {
  2781         return 0;
  2782     } else if (_this->current_glctx == NULL) {
  2783         return 0;
  2784     } else if (_this->GL_GetSwapInterval) {
  2785         return _this->GL_GetSwapInterval(_this);
  2786     } else {
  2787         return 0;
  2788     }
  2789 }
  2790 
  2791 void
  2792 SDL_GL_SwapWindow(SDL_Window * window)
  2793 {
  2794     CHECK_WINDOW_MAGIC(window, );
  2795 
  2796     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2797         SDL_SetError("The specified window isn't an OpenGL window");
  2798         return;
  2799     }
  2800     _this->GL_SwapWindow(_this, window);
  2801 }
  2802 
  2803 void
  2804 SDL_GL_DeleteContext(SDL_GLContext context)
  2805 {
  2806     if (!_this || !context) {
  2807         return;
  2808     }
  2809 
  2810     if (_this->current_glctx == context) {
  2811         SDL_GL_MakeCurrent(NULL, NULL);
  2812     }
  2813 
  2814     _this->GL_DeleteContext(_this, context);
  2815 }
  2816 
  2817 #if 0                           /* FIXME */
  2818 /*
  2819  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2820  * & 2 for alpha channel.
  2821  */
  2822 static void
  2823 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2824 {
  2825     int x, y;
  2826     Uint32 colorkey;
  2827 #define SET_MASKBIT(icon, x, y, mask) \
  2828     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2829 
  2830     colorkey = icon->format->colorkey;
  2831     switch (icon->format->BytesPerPixel) {
  2832     case 1:
  2833         {
  2834             Uint8 *pixels;
  2835             for (y = 0; y < icon->h; ++y) {
  2836                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2837                 for (x = 0; x < icon->w; ++x) {
  2838                     if (*pixels++ == colorkey) {
  2839                         SET_MASKBIT(icon, x, y, mask);
  2840                     }
  2841                 }
  2842             }
  2843         }
  2844         break;
  2845 
  2846     case 2:
  2847         {
  2848             Uint16 *pixels;
  2849             for (y = 0; y < icon->h; ++y) {
  2850                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2851                 for (x = 0; x < icon->w; ++x) {
  2852                     if ((flags & 1) && *pixels == colorkey) {
  2853                         SET_MASKBIT(icon, x, y, mask);
  2854                     } else if ((flags & 2)
  2855                                && (*pixels & icon->format->Amask) == 0) {
  2856                         SET_MASKBIT(icon, x, y, mask);
  2857                     }
  2858                     pixels++;
  2859                 }
  2860             }
  2861         }
  2862         break;
  2863 
  2864     case 4:
  2865         {
  2866             Uint32 *pixels;
  2867             for (y = 0; y < icon->h; ++y) {
  2868                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2869                 for (x = 0; x < icon->w; ++x) {
  2870                     if ((flags & 1) && *pixels == colorkey) {
  2871                         SET_MASKBIT(icon, x, y, mask);
  2872                     } else if ((flags & 2)
  2873                                && (*pixels & icon->format->Amask) == 0) {
  2874                         SET_MASKBIT(icon, x, y, mask);
  2875                     }
  2876                     pixels++;
  2877                 }
  2878             }
  2879         }
  2880         break;
  2881     }
  2882 }
  2883 
  2884 /*
  2885  * Sets the window manager icon for the display window.
  2886  */
  2887 void
  2888 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2889 {
  2890     if (icon && _this->SetIcon) {
  2891         /* Generate a mask if necessary, and create the icon! */
  2892         if (mask == NULL) {
  2893             int mask_len = icon->h * (icon->w + 7) / 8;
  2894             int flags = 0;
  2895             mask = (Uint8 *) SDL_malloc(mask_len);
  2896             if (mask == NULL) {
  2897                 return;
  2898             }
  2899             SDL_memset(mask, ~0, mask_len);
  2900             if (icon->flags & SDL_SRCCOLORKEY)
  2901                 flags |= 1;
  2902             if (icon->flags & SDL_SRCALPHA)
  2903                 flags |= 2;
  2904             if (flags) {
  2905                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2906             }
  2907             _this->SetIcon(_this, icon, mask);
  2908             SDL_free(mask);
  2909         } else {
  2910             _this->SetIcon(_this, icon, mask);
  2911         }
  2912     }
  2913 }
  2914 #endif
  2915 
  2916 SDL_bool
  2917 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2918 {
  2919     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2920 
  2921     if (!info) {
  2922         return SDL_FALSE;
  2923     }
  2924     info->subsystem = SDL_SYSWM_UNKNOWN;
  2925 
  2926     if (!_this->GetWindowWMInfo) {
  2927         return SDL_FALSE;
  2928     }
  2929     return (_this->GetWindowWMInfo(_this, window, info));
  2930 }
  2931 
  2932 void
  2933 SDL_StartTextInput(void)
  2934 {
  2935     SDL_Window *window;
  2936 
  2937     /* First, enable text events */
  2938     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2939     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2940 
  2941     /* Then show the on-screen keyboard, if any */
  2942     window = SDL_GetFocusWindow();
  2943     if (window && _this && _this->ShowScreenKeyboard) {
  2944         _this->ShowScreenKeyboard(_this, window);
  2945     }
  2946 
  2947     /* Finally start the text input system */
  2948     if (_this && _this->StartTextInput) {
  2949         _this->StartTextInput(_this);
  2950     }
  2951 }
  2952 
  2953 SDL_bool
  2954 SDL_IsTextInputActive(void)
  2955 {
  2956     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  2957 }
  2958 
  2959 void
  2960 SDL_StopTextInput(void)
  2961 {
  2962     SDL_Window *window;
  2963 
  2964     /* Stop the text input system */
  2965     if (_this && _this->StopTextInput) {
  2966         _this->StopTextInput(_this);
  2967     }
  2968 
  2969     /* Hide the on-screen keyboard, if any */
  2970     window = SDL_GetFocusWindow();
  2971     if (window && _this && _this->HideScreenKeyboard) {
  2972         _this->HideScreenKeyboard(_this, window);
  2973     }
  2974 
  2975     /* Finally disable text events */
  2976     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2977     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2978 }
  2979 
  2980 void
  2981 SDL_SetTextInputRect(SDL_Rect *rect)
  2982 {
  2983     if (_this && _this->SetTextInputRect) {
  2984         _this->SetTextInputRect(_this, rect);
  2985     }
  2986 }
  2987 
  2988 SDL_bool
  2989 SDL_HasScreenKeyboardSupport(void)
  2990 {
  2991     if (_this && _this->HasScreenKeyboardSupport) {
  2992         return _this->HasScreenKeyboardSupport(_this);
  2993     }
  2994     return SDL_FALSE;
  2995 }
  2996 
  2997 SDL_bool
  2998 SDL_IsScreenKeyboardShown(SDL_Window *window)
  2999 {
  3000     if (window && _this && _this->IsScreenKeyboardShown) {
  3001         return _this->IsScreenKeyboardShown(_this, window);
  3002     }
  3003     return SDL_FALSE;
  3004 }
  3005 
  3006 #if SDL_VIDEO_DRIVER_WINDOWS
  3007 #include "windows/SDL_windowsmessagebox.h"
  3008 #endif
  3009 #if SDL_VIDEO_DRIVER_COCOA
  3010 #include "cocoa/SDL_cocoamessagebox.h"
  3011 #endif
  3012 #if SDL_VIDEO_DRIVER_UIKIT
  3013 #include "uikit/SDL_uikitmessagebox.h"
  3014 #endif
  3015 #if SDL_VIDEO_DRIVER_X11
  3016 #include "x11/SDL_x11messagebox.h"
  3017 #endif
  3018 
  3019 int
  3020 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3021 {
  3022     int dummybutton;
  3023     int retval = -1;
  3024     SDL_bool relative_mode = SDL_GetRelativeMouseMode();
  3025     int show_cursor_prev = SDL_ShowCursor( 1 );
  3026 
  3027     SDL_SetRelativeMouseMode( SDL_FALSE );
  3028 
  3029     if (!buttonid) {
  3030         buttonid = &dummybutton;
  3031     }
  3032     if (_this && _this->ShowMessageBox) {
  3033         if (_this->ShowMessageBox(_this, messageboxdata, buttonid) == 0) {
  3034             retval = 0;
  3035         }
  3036     }
  3037 
  3038     /* It's completely fine to call this function before video is initialized */
  3039 #if SDL_VIDEO_DRIVER_WINDOWS
  3040     if ((retval == -1) && (WIN_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3041         retval = 0;
  3042     }
  3043 #endif
  3044 #if SDL_VIDEO_DRIVER_COCOA
  3045     if ((retval == -1) && (Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3046         retval = 0;
  3047     }
  3048 #endif
  3049 #if SDL_VIDEO_DRIVER_UIKIT
  3050     if ((retval == -1) && (UIKit_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3051         retval = 0;
  3052     }
  3053 #endif
  3054 #if SDL_VIDEO_DRIVER_X11
  3055     if ((retval == -1) && (X11_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3056         retval = 0;
  3057     }
  3058 #endif
  3059 
  3060     SDL_ShowCursor( show_cursor_prev );
  3061     SDL_SetRelativeMouseMode( relative_mode );
  3062 
  3063     if(retval == -1) {
  3064         SDL_SetError("No message system available");
  3065     }
  3066     return retval;
  3067 }
  3068 
  3069 int
  3070 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3071 {
  3072     SDL_MessageBoxData data;
  3073     SDL_MessageBoxButtonData button;
  3074 
  3075     SDL_zero(data);
  3076     data.flags = flags;
  3077     data.title = title;
  3078     data.message = message;
  3079     data.numbuttons = 1;
  3080     data.buttons = &button;
  3081     data.window = window;
  3082 
  3083     SDL_zero(button);
  3084     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3085     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3086     button.text = "OK";
  3087 
  3088     return SDL_ShowMessageBox(&data, NULL);
  3089 }
  3090 
  3091 SDL_bool
  3092 SDL_ShouldAllowTopmost(void)
  3093 {
  3094     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3095     if (hint) {
  3096         if (*hint == '0') {
  3097             return SDL_FALSE;
  3098         } else {
  3099             return SDL_TRUE;
  3100         }
  3101     }
  3102     return SDL_TRUE;
  3103 }
  3104 
  3105 /* vi: set ts=4 sw=4 expandtab: */