src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 08 Aug 2013 13:22:21 -0700
changeset 7609 6e1abd05047c
parent 7608 3f487d7d2d1d
child 7659 ac4ce59c40e7
child 8477 ad08f0d710f3
permissions -rw-r--r--
Backed out changeset 3f487d7d2d1d

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