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