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